* What's it's name again? @ 2002-07-29 23:13 chris.danx 2002-07-29 23:32 ` Larry Elmore 2002-07-29 23:47 ` Robert A Duff 0 siblings, 2 replies; 11+ messages in thread From: chris.danx @ 2002-07-29 23:13 UTC (permalink / raw) Hi, What do you call private types whose declaration is found in the specification but whose definition is found in the body? I remember reading/hearing that they have a name (or term) associated with them, but can't remember what it is. Are there any complications with moving type definitions to the body? (e.g. with controlled types?). Cohens' book is at the ready, just need their name or a pointer! I currently have some packages which look like package some_kind_of_data_structure is type data_structure is private; private type data_structure is Ada.Finalized.Controlled with record ... end record; end some_data_structure; but have been wondering what would happen if the definitions were moved (the obvious benefit is that the package specification does not need to be recompiled when the representation is changed, but is that really a benefit when small numbers of files are involved?) This kind of design was mentioned in passing in a Software Design course, and I wondered why people prefer one way over the other (most of the ada code I've seen uses the spec to complete the definition of a type). Just curious, that's all! Regards, Chris -- to reply change 'spamoff' to 'chris' ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-29 23:13 What's it's name again? chris.danx @ 2002-07-29 23:32 ` Larry Elmore 2002-07-30 0:08 ` chris.danx 2002-07-29 23:47 ` Robert A Duff 1 sibling, 1 reply; 11+ messages in thread From: Larry Elmore @ 2002-07-29 23:32 UTC (permalink / raw) chris.danx wrote: > Hi, > > What do you call private types whose declaration is found in the > specification but whose definition is found in the body? I remember > reading/hearing that they have a name (or term) associated with them, > but can't remember what it is. > > Are there any complications with moving type definitions to the body? > (e.g. with controlled types?). Cohens' book is at the ready, just need > their name or a pointer! I think what you want is covered in 11.2 of Cohen (p. 465 in my copy), and they're called incomplete type declarations. I'm re-learning Ada and just happened to cover that section last night. :) --Larry ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-29 23:32 ` Larry Elmore @ 2002-07-30 0:08 ` chris.danx 0 siblings, 0 replies; 11+ messages in thread From: chris.danx @ 2002-07-30 0:08 UTC (permalink / raw) Larry Elmore wrote: > chris.danx wrote: > > I think what you want is covered in 11.2 of Cohen (p. 465 in my copy), > and they're called incomplete type declarations. > > I'm re-learning Ada and just happened to cover that section last night. :) Thanks, that's the right thing. Chris ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-29 23:13 What's it's name again? chris.danx 2002-07-29 23:32 ` Larry Elmore @ 2002-07-29 23:47 ` Robert A Duff 2002-07-30 0:50 ` chris.danx ` (2 more replies) 1 sibling, 3 replies; 11+ messages in thread From: Robert A Duff @ 2002-07-29 23:47 UTC (permalink / raw) "chris.danx" <spamoff.danx@ntlworld.com> writes: > What do you call private types whose declaration is found in the > specification but whose definition is found in the body? I remember > reading/hearing that they have a name (or term) associated with them, > but can't remember what it is. That's not quite legal. I think you mean a private type completed by an access type, where the access type points to an incomplete type completed in the body. Like this: package P is type T is private; private type R; -- completed in body type T is access R; end P; package body P is type R is record ... I call R an "stt incomplete type", and I call T an "stt access type", named after Tucker Taft (initials "stt"), who invented them around 1982 or so, just before Ada 83 was standardized. Jean Ichbiah called them "Taft Amendment Types". > Are there any complications with moving type definitions to the body? > (e.g. with controlled types?). None other than the fact that you have to have a pointer type involved. If I need a pointer type anyway, then I use stt access types, but I don't normally introduce *extra* pointers just to be able to use this feature. Introducing extra pointers causes the obvious problems: how do you allocate and deallocate the pointed-to things? > I currently have some packages which look like > > package some_kind_of_data_structure is > > type data_structure is private; > > private > > type data_structure is Ada.Finalized.Controlled with record > ... > end record; > > end some_data_structure; > > but have been wondering what would happen if the definitions were > moved If you did the obvious thing of moving "type data_structure is Ada.Finalized.Controlled with record..." to the body, then you would get an error at compile time. To make it work, you have to introduce an incomplete type, and a pointer to it. > (the obvious benefit is that the package specification does not need to > be recompiled when the representation is changed, but is that really a > benefit when small numbers of files are involved?) Yes, that's the obvious benefit, and yes, the benefit depends on how much code might need to be recompiled. It could be a lot -- the transitive closure of the with's of that package spec. ---------------- The main reason normal types need to be completed in the private part (and not the body) is that the compiler wants to know their size. For example, ":=" on a private type needs to know how big it is. If it were declared in the body, the size would be a run-time quantity, resulting in an efficiency hit. (Consider also, records containing that private type. And consider pragma Pack on such records.) In fact, this sort of thing is the reason for the existence of private parts. It's OK for an incomplete type (declared in a *private part*) to be completed in the body, because, in theory, nobody outside the package cares about its size. And pointers to it are always the size of one address. (At least that's the theory -- in practise, some compilers like to have different-sized pointers depending on the designated type, and stt access types are a headache for them. Another unexpected headache is caused by stt-incomplete types that have discriminants.) Another reason to insist on "normal" types being completed in the private part might be that the parameter passing mechanism (by copy vs. by reference) depends on whether the full type is "elementary". One would not want that to be a run-time decision. The whole model here depends on the idea that the compiler can look at the specs of all with'ed packages (including private parts), but not their bodies. Pragma Inline breaks that model, which IMHO makes the whole model suspect. - Bob ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-29 23:47 ` Robert A Duff @ 2002-07-30 0:50 ` chris.danx 2002-07-30 8:21 ` Dmitry A. Kazakov 2002-07-30 18:55 ` Richard Riehle 2 siblings, 0 replies; 11+ messages in thread From: chris.danx @ 2002-07-30 0:50 UTC (permalink / raw) Robert A Duff wrote: > "chris.danx" <spamoff.danx@ntlworld.com> writes: > > That's not quite legal. I think you mean a private type completed by an > access type, where the access type points to an incomplete type > completed in the body. [snip] I must have misunderstood the code in the course. > I call R an "stt incomplete type", and I call T an "stt access type", > named after Tucker Taft (initials "stt"), who invented them around 1982 > or so, just before Ada 83 was standardized. Jean Ichbiah called them > "Taft Amendment Types". :) [snip loads of useful info] > The whole model here depends on the idea that the compiler can look at > the specs of all with'ed packages (including private parts), but not > their bodies. Pragma Inline breaks that model, which IMHO makes the > whole model suspect. Thanks for that Bob, I understand the issues a bit better now! The interest in this came from a discussion about coupling & encapsulation - it got me thinking about how much information given away to developers in the package spec. If incomplete types are used, virtually no information is given to the client developer, but for "normal" types the representation of the type is there for the any developer to see. Maybe giving such information leads *some* developers to make assumptions about the representation, which may not hold throughout the packages lifetime. Since the types are private, it's not a big deal - what information could the developer rely on? they're private after all! Sometimes I'd just like to be able to say "don't worry about how it works, just know that it does and satisfies these requirments, and don't peek!". :) > - Bob Chris p.s. I'm not critising Ada :) -- to reply by personal email change 'spamoff' to 'chris' ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-29 23:47 ` Robert A Duff 2002-07-30 0:50 ` chris.danx @ 2002-07-30 8:21 ` Dmitry A. Kazakov 2002-07-30 18:53 ` Robert A Duff 2002-07-30 18:55 ` Richard Riehle 2 siblings, 1 reply; 11+ messages in thread From: Dmitry A. Kazakov @ 2002-07-30 8:21 UTC (permalink / raw) On Mon, 29 Jul 2002 23:47:38 GMT, Robert A Duff <bobduff@shell01.TheWorld.com> wrote: >The whole model here depends on the idea that the compiler can look at >the specs of all with'ed packages (including private parts), but not >their bodies. Pragma Inline breaks that model, which IMHO makes the >whole model suspect. I find it too, but simply cannot imagine how one could do it otherwise. Do you have any idea? --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-30 8:21 ` Dmitry A. Kazakov @ 2002-07-30 18:53 ` Robert A Duff 2002-08-01 0:11 ` Dmitry A.Kazakov 0 siblings, 1 reply; 11+ messages in thread From: Robert A Duff @ 2002-07-30 18:53 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > On Mon, 29 Jul 2002 23:47:38 GMT, Robert A Duff > <bobduff@shell01.TheWorld.com> wrote: > > >The whole model here depends on the idea that the compiler can look at > >the specs of all with'ed packages (including private parts), but not > >their bodies. Pragma Inline breaks that model, which IMHO makes the > >whole model suspect. > > I find it too, but simply cannot imagine how one could do it > otherwise. Do you have any idea? I'm not sure which part you think is hard. You could put procedure bodies in specs (like in C++) and make inlining easier. Or you can put the completion of private types in the package body, making generation of efficient code harder. But not impossible -- the compiler has to assume the worst (e.g. treat the size of a private type as a dynamic quantity, or else peek into the body. The issue is that in order to generate efficient code, the compiler needs to see some part of the "implementation" of something. In the case of a type, the compiler would often like to know the size of that type (if static), so it can allocate variables and record components and whatnot efficiently. In the case of a procedure, the most efficient implementation is sometimes inlined code, so the compiler needs to see the procedure body. I'm assuming the language supports some sort of separate interface vs. implementation. By "separate" I mean some combination of "stored in separate source files" and "split clearly syntactically" and "processed separately by the compiler." (The Ada RM doesn't say anything about source files, but it heavily implies some things, and this issue is important: one would like the CM system to control interface and implementation separately.) But we don't want to include this efficiency information in the interface definition (the "spec", in Ada). Types and procedures are the main thing, but there are other analogous features: e.g., you don't want the *value* of a deferred constant to be part of the spec, but you want the compiler to take advantage of that value, if it can. There are several possible solutions. My objection in the Ada case is lack of uniformity -- solving two similar problems with completely different solutions. That is, the "private type" solution is different from the "pragma inline" solution. Here are the solutions that come to mind: 1. Make the private information part of the spec. This is what Ada does for private types -- the compiler can see the full type declaration. This is also what C++ uses for the inlined-call case: to inline something, you include the "body" in the "spec" of the class. (Please correct me if my memory of C++ is hazy.) 2. Put the private info in the body. But let the compiler "peek" into the body in some cases (pragma Inline present, inlining-enabled switch turned on, phase of moon is blue, etc). This is what Ada does for the inlined-call case. I would claim Ada *could* do something similar for the private type case. (Note that in languages where "everything's a pointer", you get this kind of (lack of) efficiency.) This idea seems nice in that it gives the programmer control over the compile-time speed vs. run-time speed trade-off. (By the way, I claim that computers are many years away from being so fast that this tradeoff doesn't matter. Especially since every hardware gain is offset by more software bloat.) 3. Define packages as *three* parts: the interface, the efficiency-critical parts of the implementation, and the implementation. The second part is really the "private part" of Ada, but split out into a separate syntactic unit (probably in a separate file). In the traditional Ada compiler dependency setup, a change to the second part would trigger recompilation of all with-ing compilation units. I claim that any of these 3 possibilities is suitable for the private-type case, and the inline-procedure case, and every other case. I also claim that it would simplify the language to choose one of the above, and use it for all such interface-vs-impl kinds of features. I lean toward 2, but 3 also has merit. Number 1, as in Ada private types, has a severe disadvantage: you can't put the full type in a different file from the private type. It doesn't get a different revision number in the CM system. And if you have multiple versions (say, for different target hardware), you have to duplicate the visible part. - Bob ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-30 18:53 ` Robert A Duff @ 2002-08-01 0:11 ` Dmitry A.Kazakov 2002-07-31 20:38 ` Robert A Duff 0 siblings, 1 reply; 11+ messages in thread From: Dmitry A.Kazakov @ 2002-08-01 0:11 UTC (permalink / raw) Robert A Duff wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > >> On Mon, 29 Jul 2002 23:47:38 GMT, Robert A Duff >> <bobduff@shell01.TheWorld.com> wrote: >> >> >The whole model here depends on the idea that the compiler can look at >> >the specs of all with'ed packages (including private parts), but not >> >their bodies. Pragma Inline breaks that model, which IMHO makes the >> >whole model suspect. >> >> I find it too, but simply cannot imagine how one could do it >> otherwise. Do you have any idea? > > I'm not sure which part you think is hard. You could put procedure > bodies in specs (like in C++) and make inlining easier. C++ is awful! All that idiotic rules that inlined function are compiled as if all class declarations were appear before the function body. Then header files of 1K+ lines long ... > Or you can put > the completion of private types in the package body, making generation > of efficient code harder. But not impossible -- the compiler has to > assume the worst (e.g. treat the size of a private type as a dynamic > quantity, or else peek into the body. > > The issue is that in order to generate efficient code, the compiler > needs to see some part of the "implementation" of something. In the > case of a type, the compiler would often like to know the size of that > type (if static), so it can allocate variables and record components and > whatnot efficiently. In the case of a procedure, the most efficient > implementation is sometimes inlined code, so the compiler needs to see > the procedure body. > > I'm assuming the language supports some sort of separate interface > vs. implementation. By "separate" I mean some combination of "stored in > separate source files" and "split clearly syntactically" and "processed > separately by the compiler." (The Ada RM doesn't say anything about > source files, but it heavily implies some things, and this issue is > important: one would like the CM system to control interface and > implementation separately.) > > But we don't want to include this efficiency information in the > interface definition (the "spec", in Ada). > > Types and procedures are the main thing, but there are other analogous > features: e.g., you don't want the *value* of a deferred constant to be > part of the spec, but you want the compiler to take advantage of that > value, if it can. > > There are several possible solutions. My objection in the Ada case is > lack of uniformity -- solving two similar problems with completely > different solutions. That is, the "private type" solution is different > from the "pragma inline" solution. I see, but there is also a difference. The body of a subroutine is not a part of its declaration, so you can continue compilation of specifications no matter how the body looks like. In contrary to this the size of a type is a function of its declaration. So there might be no difference when some other comilation unit is being compiled, but for a compilation the package's specification I think there is a difference. > Here are the solutions that come to mind: > > 1. Make the private information part of the spec. This is what Ada does > for private types -- the compiler can see the full type declaration. > This is also what C++ uses for the inlined-call case: to inline > something, you include the "body" in the "spec" of the class. > (Please correct me if my memory of C++ is hazy.) Something like: package ... is ... procedure Foo; -- To be inlined (no extra pragma) ... private ... procedure Foo is -- Implementation here begin ... end Foo; ... There is a problem that Foo will see no package body, which might contain some implementation-dependent things it needs. > 2. Put the private info in the body. But let the compiler "peek" into > the body in some cases (pragma Inline present, inlining-enabled > switch turned on, phase of moon is blue, etc). This is what Ada does > for the inlined-call case. I would claim Ada *could* do something > similar for the private type case. (Note that in languages where > "everything's a pointer", you get this kind of (lack of) efficiency.) > > This idea seems nice in that it gives the programmer control over the > compile-time speed vs. run-time speed trade-off. (By the way, I > claim that computers are many years away from being so fast that this > tradeoff doesn't matter. Especially since every hardware gain is > offset by more software bloat.) Sort of pragma Inline for incomplete types and values (deferred constants)? Do you think it is technically possible? I has not much thought about it, but we must ensure absence of any circular dependencies, which could prevent compiler from calculation of the object size. > 3. Define packages as *three* parts: the interface, the > efficiency-critical parts of the implementation, and the > implementation. > The second part is really the "private part" of Ada, but split > out into a separate syntactic unit (probably in a separate file). > In the traditional Ada compiler dependency setup, a change to the > second part would trigger recompilation of all with-ing compilation > units. This is attractive, because with tagged types [especially when you need to add some public and some private components] the specifications get too long. It is also good because then one could require that the compiler never ever looks in *.adb. But does not it also suffer the problem of not-seeing *.adb? > I claim that any of these 3 possibilities is suitable for the > private-type case, and the inline-procedure case, and every other case. > I also claim that it would simplify the language to choose one of the > above, and use it for all such interface-vs-impl kinds of features. > > I lean toward 2, but 3 also has merit. Number 1, as in Ada private > types, has a severe disadvantage: you can't put the full type in a > different file from the private type. It doesn't get a different > revision number in the CM system. And if you have multiple versions > (say, for different target hardware), you have to duplicate the visible > part. What if to allow something like: package X ... private is separate; end X; Then there should be X-XX.ads containing a completion of X. -- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-08-01 0:11 ` Dmitry A.Kazakov @ 2002-07-31 20:38 ` Robert A Duff 2002-08-02 2:21 ` Dmitry A.Kazakov 0 siblings, 1 reply; 11+ messages in thread From: Robert A Duff @ 2002-07-31 20:38 UTC (permalink / raw) Dmitry A.Kazakov <mailbox@dmitry-kazakov.de> writes: > > I'm not sure which part you think is hard. You could put procedure > > bodies in specs (like in C++) and make inlining easier. > > C++ is awful! All that idiotic rules that inlined function are compiled as > if all class declarations were appear before the function body. Then header > files of 1K+ lines long ... I'm not familiar with the details of these rules. I'm willing to believe that they are awful. > I see, but there is also a difference. The body of a subroutine is not a > part of its declaration, so you can continue compilation of specifications > no matter how the body looks like. Not if you're trying to inline the code. >... In contrary to this the size of a type > is a function of its declaration. So there might be no difference when some > other comilation unit is being compiled, but for a compilation the > package's specification I think there is a difference. I don't see any difference, in principle. If the compiler doesn't know the size of the type, it has to generate less efficient code. > > Here are the solutions that come to mind: > > > > 1. Make the private information part of the spec. This is what Ada does > > for private types -- the compiler can see the full type declaration. > > This is also what C++ uses for the inlined-call case: to inline > > something, you include the "body" in the "spec" of the class. > > (Please correct me if my memory of C++ is hazy.) > > Something like: > > package ... is > ... > procedure Foo; -- To be inlined (no extra pragma) > ... > private > ... > procedure Foo is -- Implementation here > begin > ... > end Foo; > ... Yes, something like that. This is essentially what C++ does for inlining. > There is a problem that Foo will see no package body, which might contain > some implementation-dependent things it needs. Everything Foo references must *also* be moved to the spec for this idea to work. That's annoying, but it is not in principle different from the fact that everything a private type refers to must be in the spec: type T is private; ... Max: constant := 1234; type My_Int is range 1..Max; function F return My_Int; type T is record X: My_Int := F(...); Because Ada requires the full type of T to occur in the spec, it also implicitly requires Max, My_Int, and F to be declared in the spec. > > 2. Put the private info in the body. But let the compiler "peek" into > > the body in some cases (pragma Inline present, inlining-enabled > > switch turned on, phase of moon is blue, etc). This is what Ada does > > for the inlined-call case. I would claim Ada *could* do something > > similar for the private type case. (Note that in languages where > > "everything's a pointer", you get this kind of (lack of) efficiency.) > > > > This idea seems nice in that it gives the programmer control over the > > compile-time speed vs. run-time speed trade-off. (By the way, I > > claim that computers are many years away from being so fast that this > > tradeoff doesn't matter. Especially since every hardware gain is > > offset by more software bloat.) > > Sort of pragma Inline for incomplete types and values (deferred constants)? Yeah. > Do you think it is technically possible? Yes. It would cause some pretty slow code without the Inline_Type, but that's the programmer's choice (compile-time efficiency vs run-time efficiency). >... I has not much thought about it, > but we must ensure absence of any circular dependencies, which could > prevent compiler from calculation of the object size. Yes. Ada already has a rule that type T cannot have a [sub]component of type T (the programmer has to insert a level of indirection). This rule would have to be removed, because the compiler doesn't always see the full type. This would mean that the *compiler* would be responsible for inserting the extra level of indirection. (This is similar to what happens in Java and other "everything's a pointer" sorts of languages -- in those languages, there is *always* an extra level of indirection.) Another problem is parameter passing mechanisms. Ada defines it to be by-copy for some types, by-reference for some types, and compiler-choice for some types. It would be pretty disgusting (from an efficiency point of view) if this choice had to be made at run time. But this is an Ada-specific issue. I don't like the Ada rules here, and we're talking about languae design (an Ada-like language that is not Ada), so it's fair for me to ignore this issue. > > 3. Define packages as *three* parts: the interface, the > > efficiency-critical parts of the implementation, and the > > implementation. > > The second part is really the "private part" of Ada, but split > > out into a separate syntactic unit (probably in a separate file). > > In the traditional Ada compiler dependency setup, a change to the > > second part would trigger recompilation of all with-ing compilation > > units. > > This is attractive, because with tagged types [especially when you need to > add some public and some private components] the specifications get too > long. It is also good because then one could require that the compiler > never ever looks in *.adb. But does not it also suffer the problem of > not-seeing *.adb? No big problem -- as I said above, it just means that everything referenced in the second part (transitively) has to be declared in the second part. Not necessarily their "bodies" (or "full types"), unless you want *those* inlined, too. No such thing as a free lunch. ;-) > > I claim that any of these 3 possibilities is suitable for the > > private-type case, and the inline-procedure case, and every other case. > > I also claim that it would simplify the language to choose one of the > > above, and use it for all such interface-vs-impl kinds of features. > > > > I lean toward 2, but 3 also has merit. Number 1, as in Ada private > > types, has a severe disadvantage: you can't put the full type in a > > different file from the private type. It doesn't get a different > > revision number in the CM system. And if you have multiple versions > > (say, for different target hardware), you have to duplicate the visible > > part. > > What if to allow something like: > > package X > ... > private is separate; > end X; > > Then there should be X-XX.ads containing a completion of X. Right. I think I remember the GNAT folks talking about implementing something like this. The idea was that the RM doesn't define the "source representation" of compilation_units, so there's nothing wrong with an implementation allowing (or requiring?!) the private part to be in a different file. Good idea, but if the language were designed with that in mind, it would work more smoothly in practise. The language heavily *implies* that each compilation_unit be represented as a contiguous piece of text in one file. For example, the private part syntax doesn't include the package name at the front. Also, there's the issue of with_clauses. It would be nice to attach with_clauses to the private_part. - Bob ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-31 20:38 ` Robert A Duff @ 2002-08-02 2:21 ` Dmitry A.Kazakov 0 siblings, 0 replies; 11+ messages in thread From: Dmitry A.Kazakov @ 2002-08-02 2:21 UTC (permalink / raw) Robert A Duff wrote: > Dmitry A.Kazakov <mailbox@dmitry-kazakov.de> writes: > >> I see, but there is also a difference. The body of a subroutine is not a >> part of its declaration, so you can continue compilation of >> specifications no matter how the body looks like. > > Not if you're trying to inline the code. In a specification? OK if the function is called to determine a constraint for some subtype, should that be made legal... >>... In contrary to this the size of a type >> is a function of its declaration. So there might be no difference when >> some other comilation unit is being compiled, but for a compilation the >> package's specification I think there is a difference. > > I don't see any difference, in principle. If the compiler doesn't know > the size of the type, it has to generate less efficient code. The question is how big will be the impact. If a function is not inlined it is not a disaster. If objects will be allocated in the heap instead of stack and all that depending on things looking very innocent to an untrained eye? >> There is a problem that Foo will see no package body, which might contain >> some implementation-dependent things it needs. > > Everything Foo references must *also* be moved to the spec for this idea > to work. That's annoying, but it is not in principle different from the > fact that everything a private type refers to must be in the spec: This means that a decision to inline or not should be met very early. Presently it is just an option that has no big impact on the design. >>... I has not much thought about it, >> but we must ensure absence of any circular dependencies, which could >> prevent compiler from calculation of the object size. > > Yes. Ada already has a rule that type T cannot have a [sub]component of > type T (the programmer has to insert a level of indirection). This rule > would have to be removed, because the compiler doesn't always see the > full type. This would mean that the *compiler* would be responsible for > inserting the extra level of indirection. (This is similar to what > happens in Java and other "everything's a pointer" sorts of languages -- > in those languages, there is *always* an extra level of indirection.) In other words, all types completed in the package body are wrapped by pointers. Would not it be easier to make sort of transparent pointers? package ... is type X is access all; -- Do not know which target type procedure Foo (A : X); -- A primitive operation ... end ...; package body ... is type T is ...; type X renames access all T; ... end ...; Then for a transparent pointer any its use is an equivalent to ".all". > Another problem is parameter passing mechanisms. Ada defines it to be > by-copy for some types, by-reference for some types, and compiler-choice > for some types. It would be pretty disgusting (from an efficiency point > of view) if this choice had to be made at run time. But this is an > Ada-specific issue. I don't like the Ada rules here, and we're talking > about languae design (an Ada-like language that is not Ada), so it's > fair for me to ignore this issue. You mean, that wrapped pointers are always by-copy no matter what is the target type? That's OK. > Also, there's the issue of with_clauses. It would be nice to attach > with_clauses to the private_part. Oh, yes. -- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: What's it's name again? 2002-07-29 23:47 ` Robert A Duff 2002-07-30 0:50 ` chris.danx 2002-07-30 8:21 ` Dmitry A. Kazakov @ 2002-07-30 18:55 ` Richard Riehle 2 siblings, 0 replies; 11+ messages in thread From: Richard Riehle @ 2002-07-30 18:55 UTC (permalink / raw) The question about completing an incomplete type in the package body has lots of interesting history. The name is, opaque type, and it comes from Modula-2. If Ada had followed the Modula-2 language design, there would be no private part in the package specification (Modula-2's Definition Module). All complete type definitions would be in the package body (Implementation Module). This design decsion created a problem for Modula-2 when trying to do separate compilations. The Modula-2 solution was to create "opaque types" that were referenced through a pointer mechanism. Modula-3 continues to follow some of the Modula-2 rules but simplifies this feature with some new language syntax. Ada's solution was to include a private part in the specification. This allowed the compiler developers enough information to do separate compilation at the specification level without resorting to opaque types. The example below, contributed by Robert Duff, is an example of creating an opaque type in Ada. This idiom is becoming more and more common in reusable components at some of our client sites. With Ada 83, opaque types were not too problematic. With the need for extensible types in Ada 95 a new problem arose: how to create extensible opaque types? There is a solution to this problem, but it requires additional levels of indirection. I am including some sample code at the end of this message for anyone who wants to play with it. Robert A Duff wrote: > "chris.danx" <spamoff.danx@ntlworld.com> writes: > > > What do you call private types whose declaration is found in the > > specification but whose definition is found in the body? I remember > > reading/hearing that they have a name (or term) associated with them, > > but can't remember what it is. > > That's not quite legal. I think you mean a private type completed by an > access type, where the access type points to an incomplete type > completed in the body. Like this: > > package P is > type T is private; > private > type R; -- completed in body > type T is access R; > end P; > > package body P is > type R is > record > ... > > I call R an "stt incomplete type", and I call T an "stt access type", > named after Tucker Taft (initials "stt"), who invented them around 1982 > or so, just before Ada 83 was standardized. Jean Ichbiah called them > "Taft Amendment Types". > > > Are there any complications with moving type definitions to the body? > > (e.g. with controlled types?). > > None other than the fact that you have to have a pointer type involved. > If I need a pointer type anyway, then I use stt access types, but I > don't normally introduce *extra* pointers just to be able to use this > feature. > > Introducing extra pointers causes the obvious problems: how do you > allocate and deallocate the pointed-to things? > > > I currently have some packages which look like > > > > package some_kind_of_data_structure is > > > > type data_structure is private; > > > > private > > > > type data_structure is Ada.Finalized.Controlled with record > > ... > > end record; > > > > end some_data_structure; > > From Richard Riehle. This code will compile, but we don't have it totally implemented in this sample. You can implement the Controlled type procedures as you wish, and don't forget to handle potential memory leaks. First we show the package body. -- Example of an Opaque Controlled Type -- Author: Richard Riehle, AdaWorks Software Engineering -- Permission to use this as you wish for any purpose at all. with Ada.Finalization; use Ada; package Opaque_Tagged_Type is type Opaque is tagged private; procedure Create (Data : in out Opaque); private type Opaque_Data; type Data_Reference is access all Opaque_Data; type Opaque is new Ada.Finalization.Controlled with record Value : Data_Reference; end record; procedure Initialize(Data : in out Opaque); procedure Finalize (Data : in out Opaque); procedure Adjust (Data : in out Opaque); end Opaque_Tagged_Type; -- ====================================================== Now we provide the stubbed-out code for the package body. package body Opaque_Tagged_Type is type Opaque_Data is new Ada.Finalization.Controlled with record X : Integer; Y : Integer; end record; procedure Initialize(Data : in out Opaque_Data); procedure Finalize (Data : in out Opaque_Data); procedure Adjust (Data : in out Opaque_Data); procedure Create(Data : in out Opaque) is Temp : Data_Reference := new Opaque_Data'(Ada.Finalization.Controlled with X => 0, Y => 0); begin Data.Value := Temp; end Create; procedure Initialize (Data : in out Opaque) is begin Data.Value.X := 0; Data.Value.Y := 0; end Initialize; procedure Finalize (Data : in out Opaque)is begin null; end Finalize; procedure Adjust (Data : in out Opaque)is begin null; end Adjust; procedure Initialize (Data : in out Opaque_Data) is begin null; end Initialize; procedure Finalize (Data : in out Opaque_Data)is begin null; end Finalize; procedure Adjust (Data : in out Opaque_Data)is begin null; end Adjust; end Opaque_Tagged_Type; ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2002-08-02 2:21 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-07-29 23:13 What's it's name again? chris.danx 2002-07-29 23:32 ` Larry Elmore 2002-07-30 0:08 ` chris.danx 2002-07-29 23:47 ` Robert A Duff 2002-07-30 0:50 ` chris.danx 2002-07-30 8:21 ` Dmitry A. Kazakov 2002-07-30 18:53 ` Robert A Duff 2002-08-01 0:11 ` Dmitry A.Kazakov 2002-07-31 20:38 ` Robert A Duff 2002-08-02 2:21 ` Dmitry A.Kazakov 2002-07-30 18:55 ` Richard Riehle
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox