* Full view of a private partial view cannot be a subtype @ 2017-12-03 2:14 Jere 2017-12-03 12:01 ` Jeffrey R. Carter ` (2 more replies) 0 siblings, 3 replies; 46+ messages in thread From: Jere @ 2017-12-03 2:14 UTC (permalink / raw) Say I have some type: package Base is type Instance is tagged limited private; procedure Operation(Object : in out Instance); private type Instance is tagged limited null record; procedure Operation(Object : in out Instance) is null; end Base; It might have 20 or so operations, but this is a simplified example. There are times where in another package I want to subtype Base.Instance and do renames of the operations in order to bring them all into scope (or whatever the correct term is): package New_Type1 is subtype Instance is Base.Instance; procedure Operation(Object : in out Instance); private procedure Operation(Object : in out Instance) renames Base.Operation; end New_Type1; (NOTE: is there a better way to do this?) This is all well and good, but sometimes while I as an implementer want this kind of relationship, I don't necessarily want to expose that relationship outside the private section of a package. Here I run into a problem as I cannot (as far as I can tell) do: package New_Type2 is type Instance is tagged limited private; procedure Operation(Object : in out Instance); private subtype Instance is Base.Instance; procedure Operation(Object : in out Instance renames Base.Operation; end New_Type2; as it fails with an error ("Instance" not type conformant with declaration) on the subtype line. Instead I have to do (again, unless there is a better way): package New_Type2 is type Instance is tagged limited private; procedure Operation(Object : in out Instance); private type Instance is new Base.Instance with null record; end New_Type2; package body New_Type2 is procedure Operation(Object : in out Instance) is begin Base.Instance(Object).Operation; end Operation; end New_Type2; This might be ok, but it's a lot of noise added (I now need a body for all of my operations and need to type convert parameters and any return values). I'm also not sure the semantics between the method I wanted and the method I had to use are the same (in all situations). I.E. I don't know if procedure Operation(Object : in out Instance renames Base.Operation; has the same semantics as procedure Operation(Object : in out Instance) is begin Base.Instance(Object).Operation; end Operation; My instinct says they do not. That may be ok, but I am just unsure. So I guess my question is two part: 1. Is there a way to make the full view of a private type a subtype when the partial view is not a subtype? Or am I forced to derive a new type? 2. If it isn't possible, are there any language reasons for why that must be so? Would making a full view of a type actually a subtype under the hood break something? ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 2:14 Full view of a private partial view cannot be a subtype Jere @ 2017-12-03 12:01 ` Jeffrey R. Carter 2017-12-03 13:33 ` Jere 2017-12-04 20:49 ` Randy Brukardt 2017-12-18 20:45 ` Stephen Leake 2 siblings, 1 reply; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-03 12:01 UTC (permalink / raw) On 12/03/2017 03:14 AM, Jere wrote: > > package New_Type1 is > subtype Instance is Base.Instance; > procedure Operation(Object : in out Instance); > private > procedure Operation(Object : in out Instance) renames Base.Operation; You can make the renaming visible as well. There doesn't seem to be any reason to hide the fact that Operation is a renaming of Base.Operation. > I'm also not > sure the semantics between the method I wanted and the > method I had to use are the same (in all situations). No, with a direct renaming, a call to the renaming is the same as a call to the original procedure. With a wrapper around the call to the original procedure, you have 2 calls. If you inline the wrapper then they should be equivalent. > 1. Is there a way to make the full view of a private type > a subtype when the partial view is not a subtype? Or am > I forced to derive a new type? You cannot use a subtype to complete a private type. But you're not forced to use a derived type and convert all over the place. Another option is private type T is [tagged] [limited] record V : Base.T; end record; and then refer to Object.V with no conversions. If your private type doesn't need to be tagged, you can also do private type T is array (1 .. 1) of Base.T; and then refer to Object (1), again with no conversions. Given that the bounds are static and you're always going to use a static index, I'd expect the indexing to be optimized away. -- Jeff Carter "So if I understand 'The Matrix Reloaded' correctly, the Matrix is basically a Microsoft operating system--it runs for a while and then crashes and reboots. By design, no less. Neo is just a memory leak that's too hard to fix, so they left him in ... The users don't complain because they're packed in slush and kept sedated." Marin D. Condic 65 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 12:01 ` Jeffrey R. Carter @ 2017-12-03 13:33 ` Jere 2017-12-03 14:34 ` Jeffrey R. Carter 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-03 13:33 UTC (permalink / raw) On Sunday, December 3, 2017 at 7:01:50 AM UTC-5, Jeffrey R. Carter wrote: > On 12/03/2017 03:14 AM, Jere wrote: > > > > package New_Type1 is > > subtype Instance is Base.Instance; > > procedure Operation(Object : in out Instance); > > private > > procedure Operation(Object : in out Instance) renames Base.Operation; > > You can make the renaming visible as well. There doesn't seem to be any reason > to hide the fact that Operation is a renaming of Base.Operation. Yes. Sorry about that. In my haste to covert what I had to a reduced example I forgot to make it null in the visible part. I would normally only hide that for private types. > > > I'm also not > > sure the semantics between the method I wanted and the > > method I had to use are the same (in all situations). > > No, with a direct renaming, a call to the renaming is the same as a call to the > original procedure. With a wrapper around the call to the original procedure, > you have 2 calls. If you inline the wrapper then they should be equivalent. I thought I remembered reading in the RM somewhere that if a renaming was a completion, that it was equivalent to a wrapper, but to be honest my memory isn't great. And even if I remembered correctly, I may not have understood the context of that fully. > > > 1. Is there a way to make the full view of a private type > > a subtype when the partial view is not a subtype? Or am > > I forced to derive a new type? > > You cannot use a subtype to complete a private type. But you're not forced to > use a derived type and convert all over the place. Another option is > > private > type T is [tagged] [limited] record > V : Base.T; > end record; > > and then refer to Object.V with no conversions. > Thanks! I didn't even think about nesting it like that. That'll work. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 13:33 ` Jere @ 2017-12-03 14:34 ` Jeffrey R. Carter 2017-12-03 17:44 ` Robert Eachus 2017-12-03 22:23 ` Jere 0 siblings, 2 replies; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-03 14:34 UTC (permalink / raw) On 12/03/2017 02:33 PM, Jere wrote: > > I thought I remembered reading in the RM somewhere that if a renaming was a > completion, that it was equivalent to a wrapper, but to be honest my memory > isn't great. And even if I remembered correctly, I may not have understood > the context of that fully. You're thinking of ARM 8.5.4 (7.1/1), which does say that. However, "equivalent" means that it gives the same results, not that it has to be implemented as such. If your renaming-as-body is in the pkg spec, it would be a pretty poor compiler that didn't implement a call to it the same as a call to a renaming-as-declaration. > Thanks! I didn't even think about nesting it like that. That'll work. Many people seem to think that as much as possible should be done through type extension. They act as though the only tool they have is the hammer of type extension, and so view every problem as a nail. In my experience type extension is usually best avoided whenever possible. -- Jeff Carter "So if I understand 'The Matrix Reloaded' correctly, the Matrix is basically a Microsoft operating system--it runs for a while and then crashes and reboots. By design, no less. Neo is just a memory leak that's too hard to fix, so they left him in ... The users don't complain because they're packed in slush and kept sedated." Marin D. Condic 65 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 14:34 ` Jeffrey R. Carter @ 2017-12-03 17:44 ` Robert Eachus 2017-12-03 18:50 ` Simon Wright 2017-12-03 19:03 ` Jeffrey R. Carter 2017-12-03 22:23 ` Jere 1 sibling, 2 replies; 46+ messages in thread From: Robert Eachus @ 2017-12-03 17:44 UTC (permalink / raw) On Sunday, December 3, 2017 at 9:34:51 AM UTC-5, Jeffrey R. Carter wrote: > Many people seem to think that as much as possible should be done through type > extension. They act as though the only tool they have is the hammer of type > extension, and so view every problem as a nail. In my experience type extension > is usually best avoided whenever possible. Several decades ago, there was a fun paper: "Nesting in Ada is for the birds." by Lori Clarke et. al. https://dl.acm.org/citation.cfm?id=948651 It may be time for a similar article about type extension. But it can't have quite so catchy a title. Building a type using mix-ins works nicely, but you want all the actual objects in the program to be of the (many) great grandchild type. I'll have to do more thinking about it. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 17:44 ` Robert Eachus @ 2017-12-03 18:50 ` Simon Wright 2017-12-03 22:10 ` Robert Eachus 2017-12-03 19:03 ` Jeffrey R. Carter 1 sibling, 1 reply; 46+ messages in thread From: Simon Wright @ 2017-12-03 18:50 UTC (permalink / raw) Robert Eachus <rieachus@comcast.net> writes: > Several decades ago, there was a fun paper: "Nesting in Ada is for the > birds." by Lori Clarke > et. al. https://dl.acm.org/citation.cfm?id=948651 Interesting! My own (subconscious) guidelines mean nesting is almost absent; for a start, most subprograms are fairly small. It always worries me when a nested subprogram makes uplevel references to its parent's variables. I imagine that most of us would regard a main program all of whose called subprograms were nested inside it (recursively) with horror. That said, completely forbidding declare blocks is going a step too far! ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 18:50 ` Simon Wright @ 2017-12-03 22:10 ` Robert Eachus 0 siblings, 0 replies; 46+ messages in thread From: Robert Eachus @ 2017-12-03 22:10 UTC (permalink / raw) On Sunday, December 3, 2017 at 1:50:44 PM UTC-5, Simon Wright wrote: > That said, completely forbidding declare blocks is going a step too far! Definitely. I tend to think of the structure of a main program is initialization code, and a declare block for the initializations that have to wait for a file to be read. For example, a file with a large matrix preceded by its dimensions. You can't tell how many tasks you need or where to split the file until you see the dimensions. Opening the file in a library package just seems wrong somehow. Also nonce procedures and functions to provide operations on a locally declared type are not really nesting anyway. My rule used to be that if the compiler was going to inline it, no worries. (Today's compilers are getting a bit too good at inlining. ;-) ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 17:44 ` Robert Eachus 2017-12-03 18:50 ` Simon Wright @ 2017-12-03 19:03 ` Jeffrey R. Carter 1 sibling, 0 replies; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-03 19:03 UTC (permalink / raw) On 12/03/2017 06:44 PM, Robert Eachus wrote: > > Several decades ago, there was a fun paper: "Nesting in Ada is for the birds." by Lori Clarke et. al. https://dl.acm.org/citation.cfm?id=948651 It may be time for a similar article about type extension. But it can't have quite so catchy a title. Building a type using mix-ins works nicely, but you want all the actual objects in the program to be of the (many) great grandchild type. I'll have to do more thinking about it. In 1994 there was a paper titled "Ada's Design Goals and Object-Oriented Programming" in /Ada Letters/. Not quite as many decades ago, and probably not as fun, and definitely not as catchy a title. -- Jeff Carter "So if I understand 'The Matrix Reloaded' correctly, the Matrix is basically a Microsoft operating system--it runs for a while and then crashes and reboots. By design, no less. Neo is just a memory leak that's too hard to fix, so they left him in ... The users don't complain because they're packed in slush and kept sedated." Marin D. Condic 65 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 14:34 ` Jeffrey R. Carter 2017-12-03 17:44 ` Robert Eachus @ 2017-12-03 22:23 ` Jere 2017-12-04 8:25 ` Dmitry A. Kazakov 2017-12-04 18:04 ` Jeffrey R. Carter 1 sibling, 2 replies; 46+ messages in thread From: Jere @ 2017-12-03 22:23 UTC (permalink / raw) On Sunday, December 3, 2017 at 9:34:51 AM UTC-5, Jeffrey R. Carter wrote: > On 12/03/2017 02:33 PM, Jere wrote: > > Thanks! I didn't even think about nesting it like that. That'll work. > > Many people seem to think that as much as possible should be done through type > extension. They act as though the only tool they have is the hammer of type > extension, and so view every problem as a nail. In my experience type extension > is usually best avoided whenever possible. > Well, I think either form is a bit too polar. I've always been taught that you use the tool that makes the most sense given the context. If a type has an "is a" relationship, you favor extension. But if it has a "has a" relationship, you favor composition. If the situation is unique enough, then you do something outside the norm. In this case I wasn't using extension because I thought it was the best method. I was using it because Ada doesn't provide me a good way to rename a type as part of the full view. Normally I would use subtype, but I can't do that with a private declaration (I don't want the client to have access to the "subtypedness", but I want to leverage it under the hood). Extension was my first stab at it because of the natural flow of type declarations in Ada. I did run into a snag with using composition. Some of my functions return numeric or access types that are created within the generic that I am trying to use. I'll still have to do conversions for those since I want them to retain their numeric and access properties (so a private nested type won't do). ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 22:23 ` Jere @ 2017-12-04 8:25 ` Dmitry A. Kazakov 2017-12-04 18:04 ` Jeffrey R. Carter 1 sibling, 0 replies; 46+ messages in thread From: Dmitry A. Kazakov @ 2017-12-04 8:25 UTC (permalink / raw) On 03/12/2017 23:23, Jere wrote: > Well, I think either form is a bit too polar. I've always been taught that > you use the tool that makes the most sense given the context. If a type > has an "is a" relationship, you favor extension. But if it has a "has a" > relationship, you favor composition. If the situation is unique enough, > then you do something outside the norm. These two are confusing. One is subtyping another is aggregation. In your "is-a" the right part is a type or a class of types. E.g. X is a Integer = the type of X is a subtype of Integer or, alternatively, member of Integer'Class. In your "has-a" the right part is a container, like String has Character. The left and right are unrelated types. Now there is a "has-a" related to subtyping. Ada does not have that. It is a supertype. E.g. if you could declare an interface Numeric and hang it on an existing type Integer: type Number is old Integer; -- (:-)) or supertype Number is Integer <wider range, other numbers>; Numeric has an Integer = Integer is a Numeric. Then extension is irrelevant to either "is-a" or "has-a" subtyping relation. It is an implementation detail regarding representations of two related types. You could have "is-a" with, without extension or completely abandoning another type representation, but not in Ada. Ada glues interface and representation together. That was an unfortunate design choice motivated by premature optimization in order to have view conversions. > In this case I wasn't using extension because I thought it was the best > method. I was using it because Ada doesn't provide me a good way to > rename a type as part of the full view. Normally I would use subtype, > but I can't do that with a private declaration (I don't want the client > to have access to the "subtypedness", but I want to leverage it under > the hood). Extension was my first stab at it because of the natural > flow of type declarations in Ada. Ada's subtype is another method to implement "is-a"/"has-a" relationships by borrowing representation and putting constraints. It is "is-a" for in-parameters, "has-a" for out-parameters. It is neither worse or better than extension, it is different. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 22:23 ` Jere 2017-12-04 8:25 ` Dmitry A. Kazakov @ 2017-12-04 18:04 ` Jeffrey R. Carter 2017-12-04 20:41 ` Jere 1 sibling, 1 reply; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-04 18:04 UTC (permalink / raw) On 12/03/2017 11:23 PM, Jere wrote: > > Well, I think either form is a bit too polar. I've always been taught that > you use the tool that makes the most sense given the context. If a type > has an "is a" relationship, you favor extension. But if it has a "has a" > relationship, you favor composition. If the situation is unique enough, > then you do something outside the norm. The most important thing is to create the simplest and clearest code possible. Tools must be judged by how well they help achieve this. Between type extension and composition, composition is almost always easier to read and understand. -- Jeff Carter "I would never want to belong to any club that would have someone like me for a member." Annie Hall 41 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 18:04 ` Jeffrey R. Carter @ 2017-12-04 20:41 ` Jere 2017-12-04 21:48 ` Jeffrey R. Carter 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-04 20:41 UTC (permalink / raw) On Monday, December 4, 2017 at 1:04:28 PM UTC-5, Jeffrey R. Carter wrote: > On 12/03/2017 11:23 PM, Jere wrote: > > > > Well, I think either form is a bit too polar. I've always been taught that > > you use the tool that makes the most sense given the context. If a type > > has an "is a" relationship, you favor extension. But if it has a "has a" > > relationship, you favor composition. If the situation is unique enough, > > then you do something outside the norm. > > The most important thing is to create the simplest and clearest code possible. > Tools must be judged by how well they help achieve this. Between type extension > and composition, composition is almost always easier to read and understand. > I don't disagree in general per say, but that is a very subjective thing. I don't find composition nearly as readable as you do. It has it's place and can be more readable, but (maybe it's just how I read and visualize) I find extension to be more readable in probably more cases than you typically do. It's just a personal thing with how I read. I've used and written both. In the case of the topic at hand, I do think composition leads to cleaner more readable code. I do still get stuck with some extra "noisy" conversions, but way less than the extension method in this case. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 20:41 ` Jere @ 2017-12-04 21:48 ` Jeffrey R. Carter 2017-12-05 8:20 ` Dmitry A. Kazakov ` (3 more replies) 0 siblings, 4 replies; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-04 21:48 UTC (permalink / raw) On 12/04/2017 09:41 PM, Jere wrote: >> > I don't disagree in general per say, but that is a very subjective thing. I > don't find composition nearly as readable as you do. It has it's place and > can be more readable, but (maybe it's just how I read and visualize) I find > extension to be more readable in probably more cases than you typically do. > It's just a personal thing with how I read. I've used and written both. I've never seen a realistic problem that was as readable when implemented with type extension as with composition. Perhaps the best fit of any problem with type extension is a GUI framework, since everything "is-a" widget. I have used 2 such frameworks implemented using type extension, Claw and Gnoga, and both are very difficult to understand. The derivation trees are very deep and there are a huge number of inherited operations. It's effectively impossible to know all the operations for the most commonly used types, which tend to be down at the leaves of the derivation tree. Sometimes an operation behaves differently at different levels, with no indication that this should be expected. Even with a tool like GPS, which will bring up a list of completions when you type a dot after the name of something of a tagged type, is not very helpful when the list contains hundreds of possibilities. One tends to stick with the basics described in the examples and add a few additional things through experimentation, leaving a great deal of poorly understood and unused functionality in the framework. With a composition approach you would at a minimum have a list of every operation on every type right there with the type declaration. On real code at work I have seen 4 experienced people spend a half an hour analyzing a piece of code, tracing through the spaghetti of type extensions and dispatching to figure out what it was doing. Those 2 wasted person-hours could have been reduced by a factor of 4 or more had type extension been eschewed. I have been looking at this for over 2 decades and have yet to see a counterexample. If you think you know of one I'd like to see it. Maybe I'm weird and most people have no problem understanding these things, but I've seen plenty of other experienced people have similar difficulties, so I doubt it. JP Rosen wrote a paper, "What Orientation Should Ada's Objects Take?" (IIRC) that reached a similar conclusion. -- Jeff Carter "I would never want to belong to any club that would have someone like me for a member." Annie Hall 41 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 21:48 ` Jeffrey R. Carter @ 2017-12-05 8:20 ` Dmitry A. Kazakov 2017-12-05 18:16 ` Jeffrey R. Carter 2017-12-05 12:35 ` Jere ` (2 subsequent siblings) 3 siblings, 1 reply; 46+ messages in thread From: Dmitry A. Kazakov @ 2017-12-05 8:20 UTC (permalink / raw) On 04/12/2017 22:48, Jeffrey R. Carter wrote: > With a composition approach you would at a minimum have a list of every > operation on every type right there with the type declaration. Overloaded with the same operations from other widget types. The fallacy of the argument comes straight from the point that the number of operation is just same. GPS is far worse in finding overloaded operations. If Button, Toggle_Button, Radio_Button etc were unrelated then in each event handler within a monstrous case over all possible widgets emitting the event, good luck finding their operations, cutting and pasting same code, you cannot reuse because types are unrelated. Yes, generics they will serve the final stroke to this insanity. > I have been looking at this for over 2 decades and have yet to see a > counterexample. If you think you know of one I'd like to see it. Maybe > I'm weird and most people have no problem understanding these things, > but I've seen plenty of other experienced people have similar > difficulties, so I doubt it. There are no more GUI frameworks based on overloading. Aggregation is used only for parent-child widget relationship. You are welcome to propose one. After all it is only the interface you have to design. All the implementation can be based on an existing framework with inheritance and overriding... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 8:20 ` Dmitry A. Kazakov @ 2017-12-05 18:16 ` Jeffrey R. Carter 2017-12-05 20:39 ` Dmitry A. Kazakov 0 siblings, 1 reply; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-05 18:16 UTC (permalink / raw) On 12/05/2017 09:20 AM, Dmitry A. Kazakov wrote: > > If Button, Toggle_Button, Radio_Button etc were unrelated then in each event > handler within a monstrous case over all possible widgets emitting the event, > good luck finding their operations, cutting and pasting same code, you cannot > reuse because types are unrelated. Yes, generics they will serve the final > stroke to this insanity. If that were really the way you'd design such a thing if deprived of type extension then I would to think you were incompetent to design S/W. I wouldn't do it that way. > You are welcome to propose one. After all it is only the interface you have to > design. All the implementation can be based on an existing framework with > inheritance and overriding... The problem with trying to build such a layer on top of an existing framework is that they all use the C-inspired idea of giving up your thread of control to the framework and it making calls to code you provide. That's not how it should be done in a decent language. -- Jeff Carter "I did not rob a bank. If I'd robbed a bank, everything would be great. I tried to rob a bank, is what happened, and they got me." Take the Money and Run 139 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 18:16 ` Jeffrey R. Carter @ 2017-12-05 20:39 ` Dmitry A. Kazakov 2017-12-05 21:38 ` Jeffrey R. Carter 0 siblings, 1 reply; 46+ messages in thread From: Dmitry A. Kazakov @ 2017-12-05 20:39 UTC (permalink / raw) On 2017-12-05 19:16, Jeffrey R. Carter wrote: > On 12/05/2017 09:20 AM, Dmitry A. Kazakov wrote: >> >> If Button, Toggle_Button, Radio_Button etc were unrelated then in each >> event handler within a monstrous case over all possible widgets >> emitting the event, good luck finding their operations, cutting and >> pasting same code, you cannot reuse because types are unrelated. Yes, >> generics they will serve the final stroke to this insanity. > > If that were really the way you'd design such a thing if deprived of > type extension then I would to think you were incompetent to design S/W. > I wouldn't do it that way. It was your idea not mine. Either buttons are related types or not. There are three relationships between widgets: 1. Parent-child 2. Commonalities in widget appearance and functionality, e.g. buttons, menus etc 3. Publisher-subscriber to events, messages, signals The classic GUI design uses referential aggregation for #1, [multiple] inheritance for #2, weak references for #3. It is simply impossible to use aggregation for everything just because aggregation is hierarchic. It can be only one thing you could put there. >> You are welcome to propose one. After all it is only the interface you >> have to design. All the implementation can be based on an existing >> framework with inheritance and overriding... > > The problem with trying to build such a layer on top of an existing > framework is that they all use the C-inspired idea of giving up your > thread of control to the framework and it making calls to code you > provide. That's not how it should be done in a decent language. Firstly, it has no influence on the interface design. Secondly, you can always use a task monitor and route all calls through it. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 20:39 ` Dmitry A. Kazakov @ 2017-12-05 21:38 ` Jeffrey R. Carter 0 siblings, 0 replies; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-05 21:38 UTC (permalink / raw) On 12/05/2017 09:39 PM, Dmitry A. Kazakov wrote: > > It was your idea not mine. No, I didn't express my idea. You assume you know what it is, but I suspect otherwise. I haven't seriously tried to design a GUI as I think it should be, so I may be overlooking some things. -- Jeff Carter "I did not rob a bank. If I'd robbed a bank, everything would be great. I tried to rob a bank, is what happened, and they got me." Take the Money and Run 139 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 21:48 ` Jeffrey R. Carter 2017-12-05 8:20 ` Dmitry A. Kazakov @ 2017-12-05 12:35 ` Jere 2017-12-05 18:40 ` Jeffrey R. Carter 2017-12-05 20:22 ` Randy Brukardt 2017-12-05 15:27 ` Shark8 2017-12-05 20:16 ` Randy Brukardt 3 siblings, 2 replies; 46+ messages in thread From: Jere @ 2017-12-05 12:35 UTC (permalink / raw) On Monday, December 4, 2017 at 4:48:34 PM UTC-5, Jeffrey R. Carter wrote: > On 12/04/2017 09:41 PM, Jere wrote: > >> > > I don't disagree in general per say, but that is a very subjective thing. I > > don't find composition nearly as readable as you do. It has it's place and > > can be more readable, but (maybe it's just how I read and visualize) I find > > extension to be more readable in probably more cases than you typically do. > > It's just a personal thing with how I read. I've used and written both. > > I've never seen a realistic problem that was as readable when implemented with > type extension as with composition. > > Perhaps the best fit of any problem with type extension is a GUI framework, > since everything "is-a" widget. I have used 2 such frameworks implemented using > type extension, Claw and Gnoga, and both are very difficult to understand. The > derivation trees are very deep and there are a huge number of inherited > operations. It's effectively impossible to know all the operations for the most > commonly used types, which tend to be down at the leaves of the derivation tree. > Sometimes an operation behaves differently at different levels, with no > indication that this should be expected. Even with a tool like GPS, which will > bring up a list of completions when you type a dot after the name of something > of a tagged type, is not very helpful when the list contains hundreds of > possibilities. One tends to stick with the basics described in the examples and > add a few additional things through experimentation, leaving a great deal of > poorly understood and unused functionality in the framework. > You run into the same issues with composition (only in my view worse). With composition you still have to look up each component's file to see it's operations and worse yet you have no tools that can help you extrapolate what operations are available from a higher level component. With extension you can at least use auto completion lists to see what all the options are. With composition you are stuck doing X.<see list> then X.Y.<see list> then X.Y.Z.<see list> and so on. Then the component chaining when wanting to call an ancestor's operation can quickly blow up with composition (as opposed to extension where there is a single level). You can simplify this by creating forwarding functions in the higher level components, but that is analogous to adding overloads in the higher level components for extension. For either it is optional. > With a composition approach you would at a minimum have a list of every > operation on every type right there with the type declaration. This phrasing makes me think you are comparing private composition vs public extension. If so, it would be more fair to compare private composition vs private extension. Both of those require at a minimum have a list of every operation on every type right there with the type declaration. Perhaps this is really more an issue of private vs public inheritance? > > On real code at work I have seen 4 experienced people spend a half an hour > analyzing a piece of code, tracing through the spaghetti of type extensions and > dispatching to figure out what it was doing. Those 2 wasted person-hours could > have been reduced by a factor of 4 or more had type extension been eschewed. > > I have been looking at this for over 2 decades and have yet to see a > counterexample. If you think you know of one I'd like to see it. Maybe I'm weird > and most people have no problem understanding these things, but I've seen plenty > of other experienced people have similar difficulties, so I doubt it. > > JP Rosen wrote a paper, "What Orientation Should Ada's Objects Take?" (IIRC) > that reached a similar conclusion. > I respect yall's view on this, but in either case it is still a subjective matter. There are a variety of people out there who all view things very differently. On a side note, I hope I do not sound too combative. I really do appreciate your input and your views. I've read most of your papers and have enjoyed them. Even if I don't agree with a specific point, I still try to re-evaluate my own decision based on what you are suggesting. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 12:35 ` Jere @ 2017-12-05 18:40 ` Jeffrey R. Carter 2017-12-06 12:54 ` Jere 2017-12-05 20:22 ` Randy Brukardt 1 sibling, 1 reply; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-05 18:40 UTC (permalink / raw) On 12/05/2017 01:35 PM, Jere wrote: > > You run into the same issues with composition (only in my view worse). With > composition you still have to look up each component's file to see it's > operations and worse yet you have no tools that can help you extrapolate > what operations are available from a higher level component. With extension > you can at least use auto completion lists to see what all the options are. > With composition you are stuck doing X.<see list> then X.Y.<see list> then > X.Y.Z.<see list> and so on. Then the component chaining when wanting to call > an ancestor's operation can quickly blow up with composition (as opposed to > extension where there is a single level). You can simplify this by creating > forwarding functions in the higher level components, but that is analogous > to adding overloads in the higher level components for extension. For either > it is optional. If you're lucky enough to have such a tool. I still find myself reading code without such assistance often enough that I think that code that is only readable with a tool is not readable at all. But your argument is about ease of writing, with isn't going to convince anyone who likes Ada. Ada explicitly states in the ARM Introduction that it's for code that's easy to read, not easy to write. The fact that you type more with composition is not an argument against it. But in my design a client wouldn't have X.Y.Z... It would apply an operation to a variant record X and the operation would do the correct thing for the current variant. If you needed to find the actual code executed without a tool, there's a chain of with clauses to lead you to it. You don't end up looking at an abstract subprogram with no idea where the actual subprogram is. > I respect yall's view on this, but in either case it is still a subjective > matter. There are a variety of people out there who all view things very > differently. I disagree. There are a set of S/W-engineering principles that help guide the S/W engineer to create S/W that is simple, correct, and easy to read. Every real-world use of type extension that I've seen has violated the principle of locality--that's inherent in the nature of type extension. Thus it is objectively more complex and harder to read than S/W that violates none of the principles. -- Jeff Carter "I did not rob a bank. If I'd robbed a bank, everything would be great. I tried to rob a bank, is what happened, and they got me." Take the Money and Run 139 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 18:40 ` Jeffrey R. Carter @ 2017-12-06 12:54 ` Jere 2017-12-06 18:03 ` Jeffrey R. Carter 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-06 12:54 UTC (permalink / raw) On Tuesday, December 5, 2017 at 1:40:40 PM UTC-5, Jeffrey R. Carter wrote: > > But your argument is about ease of writing, with isn't going to convince anyone > who likes Ada. Ada explicitly states in the ARM Introduction that it's for code > that's easy to read, not easy to write. The fact that you type more with > composition is not an argument against it. No, I wasn't making an argument vs ease of writing. I was saying that, for me, there are cases where composition is harder to read. > > > I respect yall's view on this, but in either case it is still a subjective > > matter. There are a variety of people out there who all view things very > > differently. > > I disagree. There are a set of S/W-engineering principles that help guide the > S/W engineer to create S/W that is simple, correct, and easy to read. Every > real-world use of type extension that I've seen has violated the principle of > locality--that's inherent in the nature of type extension. Thus it is > objectively more complex and harder to read than S/W that violates none of the > principles. > I don't think we will ever agree on this topic, because, having grown up as someone with trouble reading, I had to find alternate methods to parse through what I saw. It's easy to get overwhelmed when there is so much to read/go through. What's readable to you isn't necessarily readable to me. Hopefully we can just agree to disagree. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-06 12:54 ` Jere @ 2017-12-06 18:03 ` Jeffrey R. Carter 0 siblings, 0 replies; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-06 18:03 UTC (permalink / raw) On 12/06/2017 01:54 PM, Jere wrote: >> > I don't think we will ever agree on this topic, because, having grown up as > someone with trouble reading, I had to find alternate methods to parse > through what I saw. It's easy to get overwhelmed when there is so much > to read/go through. What's readable to you isn't necessarily readable to me. S/W is too important for those who are busy creating new buffer-overflow errors to be allowed to do it. If we're lucky, that will change. If it does, when we're applying for approval, I'd think that a history of violating S/W-engineering principles would not be a selling point. > Hopefully we can just agree to disagree. Not going to happen. You'll come around to my way of thinking or I shall taunt you a second time. -- Jeff Carter "I fart in your general direction." Monty Python & the Holy Grail 05 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 12:35 ` Jere 2017-12-05 18:40 ` Jeffrey R. Carter @ 2017-12-05 20:22 ` Randy Brukardt 1 sibling, 0 replies; 46+ messages in thread From: Randy Brukardt @ 2017-12-05 20:22 UTC (permalink / raw) "Jere" <jhb.chat@gmail.com> wrote in message news:c6fef139-6718-4c05-8791-897e995bdb4c@googlegroups.com... > On Monday, December 4, 2017 at 4:48:34 PM UTC-5, Jeffrey R. Carter wrote: ... > I respect yall's view on this, but in either case it is still a subjective > matter. There are a variety of people out there who all view things very > differently. Jeff's opinion on type extension seems to be the most extreme here on c.l.a so that isn't surprising. (Full discloser: I'm probably the second-most extreme.) Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 21:48 ` Jeffrey R. Carter 2017-12-05 8:20 ` Dmitry A. Kazakov 2017-12-05 12:35 ` Jere @ 2017-12-05 15:27 ` Shark8 2017-12-05 18:50 ` Jeffrey R. Carter 2017-12-05 20:59 ` Randy Brukardt 2017-12-05 20:16 ` Randy Brukardt 3 siblings, 2 replies; 46+ messages in thread From: Shark8 @ 2017-12-05 15:27 UTC (permalink / raw) On Monday, December 4, 2017 at 2:48:34 PM UTC-7, Jeffrey R. Carter wrote: > On 12/04/2017 09:41 PM, Jere wrote: > >> > > I don't disagree in general per say, but that is a very subjective thing. I > > don't find composition nearly as readable as you do. It has it's place and > > can be more readable, but (maybe it's just how I read and visualize) I find > > extension to be more readable in probably more cases than you typically do. > > It's just a personal thing with how I read. I've used and written both. > > I've never seen a realistic problem that was as readable when implemented with > type extension as with composition. > > Perhaps the best fit of any problem with type extension is a GUI framework, > since everything "is-a" widget. I have used 2 such frameworks implemented using > type extension, Claw and Gnoga, and both are very difficult to understand. The > derivation trees are very deep and there are a huge number of inherited > operations. It's effectively impossible to know all the operations for the most > commonly used types, which tend to be down at the leaves of the derivation tree. One of the best GUI frameworks I've seen is Delphi's VCL -- it is very good in this respect having several "base level" types where you'll look for common operations. (There's one for visual-components, one for nonvisual-components, and they both share an ancestor that is [IIRC] higher than TObject.) Besides UIs, the one problem that springs immediately to mind is the internals of a compiler's IR/parse-tree. Another is linguistics (though I haven't actually seen this used) where you are modelling language on a abstract/general level: Types Verb & Noun, descending from Word. Phrases, sentences, etc. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 15:27 ` Shark8 @ 2017-12-05 18:50 ` Jeffrey R. Carter 2017-12-05 20:59 ` Randy Brukardt 1 sibling, 0 replies; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-05 18:50 UTC (permalink / raw) On 12/05/2017 04:27 PM, Shark8 wrote: > > Besides UIs, the one problem that springs immediately to mind is the internals of a compiler's IR/parse-tree. Another is linguistics (though I haven't actually seen this used) where you are modelling language on a abstract/general level: Types Verb & Noun, descending from Word. Phrases, sentences, etc. Do most compilers use type extension for that? If not, it would be interesting to know why. -- Jeff Carter "I did not rob a bank. If I'd robbed a bank, everything would be great. I tried to rob a bank, is what happened, and they got me." Take the Money and Run 139 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 15:27 ` Shark8 2017-12-05 18:50 ` Jeffrey R. Carter @ 2017-12-05 20:59 ` Randy Brukardt 2017-12-05 22:43 ` Shark8 1 sibling, 1 reply; 46+ messages in thread From: Randy Brukardt @ 2017-12-05 20:59 UTC (permalink / raw) "Shark8" <onewingedshark@gmail.com> wrote in message news:43498b2a-773c-454a-b0e7-ade5d6594bd4@googlegroups.com... ... >Besides UIs, the one problem that springs immediately to mind is the >internals of a >compiler's IR/parse-tree. I can speak to this (at least somewhat), and I think the full OOP version would be a nightmare. Janus/Ada (originally designed in the early 1980s, before there was such a thing as type extension) uses variant records controlled by enumeration discriminants. That is a very effective organization in Ada, because of two features of Ada not found in most other languages - case completeness and variant component checks. Case completeness means that adding/removing a variant is relatively easy: most case statements that need changing are called out by the compiler. Time has proven that it isn't even worth looking for change locations since the compiler will point them out much quicker than one can find them. Similarly, adding/removing/moving/modifying components in the variant either cause compiler errors (see above) or runtime errors from accessing non-existent components. With good testing (easy for an Ada compiler - the ACATS provides the needed foundation), the runtime errors will point out the majority of other changes needed. Indeed, I've been introducing additional variants into the Janus/Ada data structures in order to get even more advantage from these features -- they eliminate large amounts of debugging that would otherwise been necessary. I've never tried an OOP compiler tree, but the Claw Builder uses an OOP organization both for the GUI and for the code generation. And that did not really work out well. There is so much boilerplate that has to be constructed for every new widget type (to declare all of the overriding routines, to provide basic implementations for those routines, and the like) that there is a strong dis-incentive to adding new widgets. (The last time I tried to add a widget, it took over 2 days solid coding to get to a compilable type.) And the boilerplate didn't seem (for Ada) to make anything easier to implement or debug. Similarly, adding a new kind of code generation (something that happens frequently with the Builder, probably would happen fairly often for a compiler as well) is a nightmare, as the new dispatching routine has to be added to every existing widget. By abandoning traditional OOP, one could do a bit better (especially by implementing many concrete operations in the root classes -- meaning, in Ada terms, that they can't be interfaces), and maybe some of the boilerplate could be reduced - but to do so, you'd have to introduce even more operations. The number of dispatching operations alone was becoming daunting. Thus, I'm unconvinced that a compiler data structure would be any advantage written in OOP (at least, if the "conventional" version was written in Ada). I suspect the reason that OOP held some much advantage to many programmers (read, C programmers) is that they had a language which provided no help at all for "conventional" programming, while Ada already had information hiding, true privacy, case completeness, variant component checks, array index checks, etc. So the increment is so much less. I think the only place OOP really holds an advantage is for programs based around call-backs (like most GUIs). And I think you'd be nuts to use call-backs if you don't have to, so there isn't much need for OOP (assuming it is compared to "conventional" Ada and some some other language that lets one do anything, no matter how unintended). Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 20:59 ` Randy Brukardt @ 2017-12-05 22:43 ` Shark8 2017-12-07 0:52 ` Randy Brukardt 0 siblings, 1 reply; 46+ messages in thread From: Shark8 @ 2017-12-05 22:43 UTC (permalink / raw) On Tuesday, December 5, 2017 at 1:59:05 PM UTC-7, Randy Brukardt wrote: > "Shark8" wrote in message > news:43498b2a-773c-454a-b0e7-ade5d6594bd4googlegroups.com... > ... > >Besides UIs, the one problem that springs immediately to mind is the > >internals of a > >compiler's IR/parse-tree. > > I can speak to this (at least somewhat), and I think the full OOP version > would be a nightmare. For [only] the Parse-tree/IR? I honestly don't see why it wouldn't work as a hierarchy, and in fact think it would naturally go that way, especially in an Ada program where you have trees all over the place: the library-hierarchy, nesting of various Ada-elements (package, subprogram, task), etc. Additionally, there are different extensions that could be made on a particular 'node' -- say the formal generic parameters for a generic. Here's an interesting tutorial on Pratt Parsing that illustrates the technique (albeit in Java), but while it's on parsing in-general it shows how the elements constructed can be "smart" enough to construct themselves* -- http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ * Example: Type If_Conditional is new Node with record Test : Boolean_Expression; Branch : Statement_Sequence; end record --... Type If_Else_Conditional is new If_Conditional with record Alternative : Statement_Sequence; end record --... > > Janus/Ada (originally designed in the early 1980s, before there was such a > thing as type extension) uses variant records controlled by enumeration > discriminants. That is a very effective organization in Ada, because of two > features of Ada not found in most other languages - case completeness and > variant component checks. Variant-records are quite good, IMO. There's been several times where working in another OOP-language I've wished I could use Ada due to the case-completeness and/or component-checks. (I view the component checks as merely a special-case/-application of the completeness-checks; the coverage seems like it ought to be "the same" [or at least generalizable like a sort].) > > Thus, I'm unconvinced that a compiler data structure would be any advantage > written in OOP (at least, if the "conventional" version was written in Ada). > I suspect the reason that OOP held some much advantage to many programmers > (read, C programmers) is that they had a language which provided no help at > all for "conventional" programming, while Ada already had information > hiding, true privacy, case completeness, variant component checks, array > index checks, etc. So the increment is so much less. > > I think the only place OOP really holds an advantage is for programs based > around call-backs (like most GUIs). And I think you'd be nuts to use > call-backs if you don't have to, so there isn't much need for OOP (assuming > it is compared to "conventional" Ada and some some other language that lets > one do anything, no matter how unintended). The above example does make use of the "use a classwide object to get around passing a subprogram" trick that was mentioned here on C.L.A a few years back -- http://computer-programming-forum.com/44-ada/30caa21641c1ed2d.htm ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 22:43 ` Shark8 @ 2017-12-07 0:52 ` Randy Brukardt 0 siblings, 0 replies; 46+ messages in thread From: Randy Brukardt @ 2017-12-07 0:52 UTC (permalink / raw) >"Shark8" <onewingedshark@gmail.com> wrote in message >news:f73127a6-2334-430b-80a0-0ac9b9519e89@googlegroups.com... >On Tuesday, December 5, 2017 at 1:59:05 PM UTC-7, Randy Brukardt wrote: >> "Shark8" wrote in message >> news:43498b2a-773c-454a-b0e7-ade5d6594bd4googlegroups.com... >> ... >> >Besides UIs, the one problem that springs immediately to mind is the >> >internals of a >> >compiler's IR/parse-tree. >> >> I can speak to this (at least somewhat), and I think the full OOP version >> would be a nightmare. > >For [only] the Parse-tree/IR? >I honestly don't see why it wouldn't work as a hierarchy, and in fact think >it would naturally go that way, especially in an Ada program where you >have trees all over the place: the library-hierarchy, nesting of various >Ada-elements (package, subprogram, task), etc. Of course there is a hierarchy, but that is the least interesting feature of "full OOP" as I understand it. (Especially as a variant record is also a representation of a hierarchy.) A "full OOP" version has to use dispatching operations for essentially all operations on the parse-tree. But there are a *lot* of those operations. Just consider tree walks. Janus/Ada has five primary expression tree walks (remember, Janus/Ada doesn't use trees for anything bigger than an expression), and a number of secondary ones. These don't all walk the tree in the same way, given the different purposes. So one ends up with a whole bunch of primitive routines that walk the tree for different purposes and in slightly different ways. When you create a new kind of node (which should be fairly frequent for an agile programmers), you have to write bodies for all of these routines. A lot of the code of each routine is similar, but sharing that code is hard, given that it is interspresed with the other stuff that the tree walk is doing. For me (in the Claw Builder), it felt like implementing a lot of boilerplate. Then you have similar things for code generation, serialization (to read trees in and out), and so on. This sort of thing makes agile programming rather difficult (and I thought that big-bang programming was mostly dead), as one can't even compile (much less test) the new node until all of those routines exist somehow. That took a very long time investment for the Claw Builder, and I suspect a real compiler would be even worse. Worse, if you find you need a new kind of tree walk part way through development, you have to add a new kind of dispatching routine to the root of the tree, and then add implementations to every node type. That takes forever, and is absolutely not agile programming. Certainly, there are some tools that could help some, but my experience suggests that >Here's an interesting tutorial on Pratt Parsing that illustrates the >technique (albeit in >Java), but while it's on parsing in-general it shows how the elements >constructed >can be "smart" enough to construct themselves* This is no problem to do (as noted above), the problem is that the result is very hard to modify. And if you are building something large and long-lived like an Ada compiler, you WILL have to modify it a lot. Maybe Ada 2020 comes out, maybe you need to implement a new code generation technique (to improve performance or fix a problem with the existing one). Modifications of OOP designs are inside-out: what usually would be a local changes (say a special tree walk to be used in a generic instantiation case) tend to have to be done globally (a new dispatching routine has to be added to every node), and global changes (like adding a new node) tend to be more local. The problem with that is that adding a new node is rather rare (the Ada 2012 changes are the first new expression nodes in Janus/Ada since about 1990), while local fixes to fix bugs are rather common. You might be able to avoid this problem by abandoning OOP for significant parts of the code, but the OOP structure is not then gaining anything about extra work to write every dispatching routine. Someone who has never used variant records in Ada might not realize how strong a solution that they actually are to these sorts of problems, and thus might think that an OOP solution is the only way to go. But that's not really true. Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 21:48 ` Jeffrey R. Carter ` (2 preceding siblings ...) 2017-12-05 15:27 ` Shark8 @ 2017-12-05 20:16 ` Randy Brukardt 2017-12-05 21:29 ` Jeffrey R. Carter 3 siblings, 1 reply; 46+ messages in thread From: Randy Brukardt @ 2017-12-05 20:16 UTC (permalink / raw) "Jeffrey R. Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message news:p04frg$q8n$1@dont-email.me... ... > Perhaps the best fit of any problem with type extension is a GUI > framework, since everything "is-a" widget. I have used 2 such frameworks > implemented using type extension, Claw and Gnoga, and both are very > difficult to understand. The derivation trees are very deep and there are > a huge number of inherited operations. It's effectively impossible to know > all the operations for the most commonly used types, which tend to be down > at the leaves of the derivation tree. Not impossible, just impossible by reading the source code. The Claw documentation materializes all of the inherited routines so that there is a cohesive list of all of the operations available for each time in the documentation. (Needless to say, this documentation is generated by an automated tool with annotations.) ... > Sometimes an operation behaves differently at different levels, with no > indication that this should be expected. Reading the super-secret documentation would help, I hope. ;-) I realize that real programmers don't need (or look at) documentation, but it is impossible to convey everything important in Ada source code! Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 20:16 ` Randy Brukardt @ 2017-12-05 21:29 ` Jeffrey R. Carter 2017-12-07 0:04 ` Randy Brukardt 0 siblings, 1 reply; 46+ messages in thread From: Jeffrey R. Carter @ 2017-12-05 21:29 UTC (permalink / raw) On 12/05/2017 09:16 PM, Randy Brukardt wrote: > > Not impossible, just impossible by reading the source code. The Claw > documentation materializes all of the inherited routines so that there is a > cohesive list of all of the operations available for each time in the > documentation. (Needless to say, this documentation is generated by an > automated tool with annotations.) By "know", I mean keep in my head. Like Dijkstra, I have only a small brain, and have to figure out ways to deal with my inability to keep an entire S/W system in my head at once. So for me, at least, even with that it's impossible. You big-brained types might have it easier. > Reading the super-secret documentation would help, I hope. ;-) For the real cases I've experienced recently, I think I read everything available. > I realize that real programmers don't need (or look at) documentation, but > it is impossible to convey everything important in Ada source code! Clearly that needs to be fixed in Ada 2X. -- Jeff Carter "I did not rob a bank. If I'd robbed a bank, everything would be great. I tried to rob a bank, is what happened, and they got me." Take the Money and Run 139 ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 21:29 ` Jeffrey R. Carter @ 2017-12-07 0:04 ` Randy Brukardt 0 siblings, 0 replies; 46+ messages in thread From: Randy Brukardt @ 2017-12-07 0:04 UTC (permalink / raw) "Jeffrey R. Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message news:p0733u$b8e$1@dont-email.me... > On 12/05/2017 09:16 PM, Randy Brukardt wrote: ... >> Reading the super-secret documentation would help, I hope. ;-) > > For the real cases I've experienced recently, I think I read everything > available. A tool like the one we created for Claw probably would be a good thing for any Ada program using type extension. (Our tool was cobbled together from various existing things without worrying about ease-of-use at all; I can barely figure out how to use it, so I don't think it would be a candidate for that tool.) No human can figure out what routines are inherited and thus available to be called. Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 2:14 Full view of a private partial view cannot be a subtype Jere 2017-12-03 12:01 ` Jeffrey R. Carter @ 2017-12-04 20:49 ` Randy Brukardt 2017-12-05 12:56 ` Jere 2017-12-18 20:45 ` Stephen Leake 2 siblings, 1 reply; 46+ messages in thread From: Randy Brukardt @ 2017-12-04 20:49 UTC (permalink / raw) "Jere" <jhb.chat@gmail.com> wrote in message news:c6ba70e3-bfd0-42ca-b742-dc472965eea0@googlegroups.com... ... > package New_Type1 is > subtype Instance is Base.Instance; > procedure Operation(Object : in out Instance); > > private > > procedure Operation(Object : in out Instance) renames Base.Operation; > end New_Type1; > > (NOTE: is there a better way to do this?) No, no better way yet, but maybe (large maybe here) in Ada 2020. (I'm leaving out all details because none have been determined yet and perhaps never will be for Ada 2020.) > This is all well and good, but sometimes while I as an implementer > want this kind of relationship, I don't necessarily want to expose > that relationship outside the private section of a package. Here I > run into a problem as I cannot (as far as I can tell) do: > > package New_Type2 is > type Instance is tagged limited private; > procedure Operation(Object : in out Instance); > private > subtype Instance is Base.Instance; This is illegal; a private type has to be completed with a full type, not a subtype. (If you have a compiler that is allowing this, it is confused...) > procedure Operation(Object : in out Instance) renames Base.Operation; ...which makes Instance a different type, and that makes this illegal (if the type declaration is written properly). > end New_Type2; Usually, you're better off allowing the relationship between types to be visible. In that case, this happens automatically. Otherwise, you can usually do this with this a "squirreling" rename (essentially, you have to rename the inherited entity before declaring the new one). However, in this case, you've hidden the inherited operation before you can rename it, so you can't do this. If you wanted a different operation name, it would work: package New_Type3 is type Instance is tagged limited private; procedure Other_Operation(Object : in out Instance); private type Instance is new Base.Instance with record ... end record; procedure Other_Operation(Object : in out Instance) renames Operation; -- (1) end New_Type3; At (1), you are renaming the operation inherited from Base.Instance. That operation isn't visible to clients, only within this package. And it has the correct types. The main use for a "squirrelling" rename is to be able to call the original operation in a overridden operation: package New_Type4 is type Instance is new Base.Instance with record ... end record; -- Operation is inherited here, with the profile: --procedure Operation (Object : in out Instance); private procedure Original_Operation(Object : in out Instance) renames Operation; -- (1) overriding procedure Operation (Object : in out Instance); end New_Type4; The declaration at (1) allows the body of Operation to call the body of Base.Operation (but with the proper types). Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-04 20:49 ` Randy Brukardt @ 2017-12-05 12:56 ` Jere 2017-12-05 20:12 ` Randy Brukardt 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-05 12:56 UTC (permalink / raw) On Monday, December 4, 2017 at 3:49:54 PM UTC-5, Randy Brukardt wrote: > "Jere" wrote in message > ... > > package New_Type1 is > > subtype Instance is Base.Instance; > > procedure Operation(Object : in out Instance); > > > > private > > > > procedure Operation(Object : in out Instance) renames Base.Operation; > > end New_Type1; > > > > (NOTE: is there a better way to do this?) > > No, no better way yet, but maybe (large maybe here) in Ada 2020. (I'm > leaving out all details because none have been determined yet and perhaps > never will be for Ada 2020.) Sounds intriguing! > > > This is all well and good, but sometimes while I as an implementer > > want this kind of relationship, I don't necessarily want to expose > > that relationship outside the private section of a package. Here I > > run into a problem as I cannot (as far as I can tell) do: > > > > package New_Type2 is > > type Instance is tagged limited private; > > procedure Operation(Object : in out Instance); > > private > > subtype Instance is Base.Instance; > > This is illegal; a private type has to be completed with a full type, not a > subtype. (If you have a compiler that is allowing this, it is confused...) Yep, that was my comment. Basically I have a low level package that is used to create many higher level, more client friendly packages: generic type Input_Type(<>); with procedure Really_Dangerous_To_Call(Object : Input_Type); Value : Integer; package Low_Level_Package type My_Type is private; type Numeric_Type is <some implementation using Value>; function Client_Friendly_Procedure (Object : My_Type) return Numeric_Type; <other operations> private ... end Low_Level_Package; and I want to use it to make some more client friendly versions. The procedure, Really_Dangerous_To_Call, isn't meant to be called directly for a client. It is meant to be used to setup implementations behind the client packages. At current my choices seem to be: subtyping: generic type Input_Type is limited private; package High_Level_Package procedure Client_Please_Do_Not_Call(Object : Input_Type); package I_Really_Wanted_To_Hide_You is new Low_Level_Package (Input_Type => Input_Type, Really_Dangerous_To_Call => Client_Please_Do_Not_Call, Value => <some value>); subtype My_Type is I_Really_Wanted_To_Hide_You.My_Type; subtype Numeric_Type is I_Really_Wanted_To_Hide_You.Numeric_Type function Client_Friendly_Procedure (Object : My_Type) return Numeric_Type renames I_Really_Wanted_To_Hide_You.Client_Friendly_Procedure; <other operations> end High_Level_Package; which exposes operations and values I do not want to expose in a more client friendly package. Currently in Ada there isn't a way that I have found to use subtyping for this in a private manner. Instead I either need to bite the bullet and expose those details (ugh), or I need to use extension or composition, of which composition is less noisy, but both will end up requiring some noisy code and possibly extra unnecessary overhead (depending on how the type conversions work out). So here the tradeoff appears to be readability vs overhead, which I don't feel it needs to be in this case, but I haven't found a good Ada building block that gives me both. > <SNIPPED> > At (1), you are renaming the operation inherited from Base.Instance. That > operation isn't visible to clients, only within this package. And it has the > correct types. > > The main use for a "squirrelling" rename is to be able to call the original > operation in a overridden operation: > > package New_Type4 is > type Instance is new Base.Instance with record ... end record; > -- Operation is inherited here, with the profile: > --procedure Operation (Object : in out Instance); > private > > procedure Original_Operation(Object : in out Instance) renames > Operation; -- (1) > overriding > procedure Operation (Object : in out Instance); > end New_Type4; > > The declaration at (1) allows the body of Operation to call the body of > Base.Operation (but with the proper types). > > Randy. This is an option I use sometimes. In this case I was hoping to keep all the interfaces named the same. I typed this up hurriedly, so I apologize if I made a typo. I hope the meaning is conveyed better though. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 12:56 ` Jere @ 2017-12-05 20:12 ` Randy Brukardt 2017-12-17 15:26 ` Jere 0 siblings, 1 reply; 46+ messages in thread From: Randy Brukardt @ 2017-12-05 20:12 UTC (permalink / raw) "Jere" <jhb.chat@gmail.com> wrote in message news:5b32a99e-04e5-4adb-8b42-88e485570641@googlegroups.com... > On Monday, December 4, 2017 at 3:49:54 PM UTC-5, Randy Brukardt wrote: >> "Jere" wrote in message >> ... >> > package New_Type1 is >> > subtype Instance is Base.Instance; >> > procedure Operation(Object : in out Instance); >> > >> > private >> > >> > procedure Operation(Object : in out Instance) renames >> > Base.Operation; >> > end New_Type1; >> > >> > (NOTE: is there a better way to do this?) >> >> No, no better way yet, but maybe (large maybe here) in Ada 2020. (I'm >> leaving out all details because none have been determined yet and perhaps >> never will be for Ada 2020.) > > Sounds intriguing! > >> >> > This is all well and good, but sometimes while I as an implementer >> > want this kind of relationship, I don't necessarily want to expose >> > that relationship outside the private section of a package. Here I >> > run into a problem as I cannot (as far as I can tell) do: >> > >> > package New_Type2 is >> > type Instance is tagged limited private; >> > procedure Operation(Object : in out Instance); >> > private >> > subtype Instance is Base.Instance; >> >> This is illegal; a private type has to be completed with a full type, not >> a >> subtype. (If you have a compiler that is allowing this, it is >> confused...) > > Yep, that was my comment. Basically I have a low level package that is > used > to create many higher level, more client friendly packages: > > generic > type Input_Type(<>); > with procedure Really_Dangerous_To_Call(Object : Input_Type); > Value : Integer; > package Low_Level_Package > > type My_Type is private; > type Numeric_Type is <some implementation using Value>; > > function Client_Friendly_Procedure > (Object : My_Type) > return Numeric_Type; > > <other operations> > > private > ... > > end Low_Level_Package; > > and I want to use it to make some more client friendly versions. > The procedure, Really_Dangerous_To_Call, isn't meant to be called > directly for a client. It is meant to be used to setup implementations > behind the client packages. If you control the entire design of the type hierarchy, the best way to do this is to put "Really_Dangerous_to_Call" into the private part of the root operation, and declare the child types in child packages. Then, the child types can call the routine but clients cannot. (An added advantage is that Really_Dangerous_to_Call can be dispatching in such a design.) Claw is organized this way, so it's pretty certain that Ada compilers can properly process such an organization. This looks something like: package Claw is ... -- Hundreds of lines of other stuff... type Root_Window_Type is abstract tagged private; -- Actually, derived from Controlled. ... -- Public dispatching operations available for all Windows, like Move, Resize, etc. private procedure Really_Dangerous_to_Call (Window : in out Root_Window_Type); -- Other private dispatching operations and the full declaration of Root_Window_Type. end Claw; package Claw.Basic is type Basic_Window_Type is new Root_Window_Type with private; ... -- Public for Basic_Windows, including those available for all Windows, like Move, Resize, etc. private -- Can override Really_Dangerous_to_Call here, if needed. end Claw.Basic; The body of Claw.Basic can call Really_Dangerous_to_Call if needed, but clients can't. If you only need class-wide operations, you can also do this with a private package (which then can only be withed by children of the parent package, and not visibly). Claw uses this to hide the actual message handlers from the clients (so the client can't mess them up), and uses dispatching to call them (so each Claw type can have a custom message handler if needed -- and it is usually needed). Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-05 20:12 ` Randy Brukardt @ 2017-12-17 15:26 ` Jere 2017-12-17 15:39 ` Dmitry A. Kazakov 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-17 15:26 UTC (permalink / raw) On Tuesday, December 5, 2017 at 3:12:43 PM UTC-5, Randy Brukardt wrote: > "Jere" wrote in message > > On Monday, December 4, 2017 at 3:49:54 PM UTC-5, Randy Brukardt wrote: > >> "Jere" wrote in message > >> ... > >> > package New_Type1 is > >> > subtype Instance is Base.Instance; > >> > procedure Operation(Object : in out Instance); > >> > > >> > private > >> > > >> > procedure Operation(Object : in out Instance) renames > >> > Base.Operation; > >> > end New_Type1; > >> > > >> > (NOTE: is there a better way to do this?) > >> > >> No, no better way yet, but maybe (large maybe here) in Ada 2020. (I'm > >> leaving out all details because none have been determined yet and perhaps > >> never will be for Ada 2020.) > > > > Sounds intriguing! > > > >> > >> > This is all well and good, but sometimes while I as an implementer > >> > want this kind of relationship, I don't necessarily want to expose > >> > that relationship outside the private section of a package. Here I > >> > run into a problem as I cannot (as far as I can tell) do: > >> > > >> > package New_Type2 is > >> > type Instance is tagged limited private; > >> > procedure Operation(Object : in out Instance); > >> > private > >> > subtype Instance is Base.Instance; > >> > >> This is illegal; a private type has to be completed with a full type, not > >> a > >> subtype. (If you have a compiler that is allowing this, it is > >> confused...) > > > > Yep, that was my comment. Basically I have a low level package that is > > used > > to create many higher level, more client friendly packages: > > > > generic > > type Input_Type(<>); > > with procedure Really_Dangerous_To_Call(Object : Input_Type); > > Value : Integer; > > package Low_Level_Package > > > > type My_Type is private; > > type Numeric_Type is <some implementation using Value>; > > > > function Client_Friendly_Procedure > > (Object : My_Type) > > return Numeric_Type; > > > > <other operations> > > > > private > > ... > > > > end Low_Level_Package; > > > > and I want to use it to make some more client friendly versions. > > The procedure, Really_Dangerous_To_Call, isn't meant to be called > > directly for a client. It is meant to be used to setup implementations > > behind the client packages. > > If you control the entire design of the type hierarchy, the best way to do > this is to put "Really_Dangerous_to_Call" into the private part of the root > operation, and declare the child types in child packages. Then, the child > types can call the routine but clients cannot. (An added advantage is that > Really_Dangerous_to_Call can be dispatching in such a design.) > > <SNIPPED Claw example> > Randy. Thanks! I think that still leaves me with the same issue. All I really want out of the client package is that it implements subtypes and renames of the hidden package. I don't really want to derive or extend or even do composition if I have to because it leads to a lot of code that is easy to mistype, difficult to parse through and read later on, and possibly add overhead (not normally an issue, but this is a low level core library for me so I at least have to consider my implementation some). All for no readability benefit (and actual detriment to reading). my assertion is that: subtype Thing is Core_Pkg.Thing; procedure Do_Something(The_Thing : in out Thing) renames Core_Pkg.Do_Something; is easier to both maintain and read than: type Thing is new Core_Pkg.Thing with null record; procedure Do_Something(The_Thing : in out Thing); ... procedure Do_Something(The_Thing : in out Thing) is begin Core_Pkg.Thing(The_Thing).Do_Something; end Do_Something; and: type Thing is record Parent_Thing : Core_Pkg.Thing; end record; procedure Do_Something(The_Thing : in out Thing); ... procedure Do_Something(The_Thing : in out Thing) is begin The_Thing.Parent_Thing.Do_Something; end Do_Something; The first option completely conveys how I want to implement it while the latter two options require additional code that adds no extra readability and gives the reader/maintainer even more to parse through (additional files and additional code) in order to determine what is going on. Furthermore it opens the maintainer up to more mistakes if this needs to be done for a lot of functions (20+). Additionally, the complexity in both reading and maintainability only gets worse if the operation signatures use multiple types that all need this same treatment. I don't mind writing the extra stuff if it gives me more readability or safety, but in this case it just feels like I am trading up readability for more writing, which I don't like doing. I like things easy to read. You're correct in that using private packages hides the Really_Dangerous_To_Call uses, but I'm still left with the original issue that I am making my code more unreadable to do so. I know that, based on this email chain, the latter two are my only options. I was just hoping there was a third option involving encapsulation of subtypes. Out of the two later approaches, composition fairs much better in readability (and possible overhead). It just has much less readability than the subtype method. I can try to give better specifics if that helps. I try to avoid that in C.L.A though as it ends up sending people down paths that are tangential, and my original question gets lost. Also it helps to keep things simple so that people can more easily help/answer. I realize the onus is on me to be better at explaining what I need though. So if you need better specifics, I can do better to provide them. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-17 15:26 ` Jere @ 2017-12-17 15:39 ` Dmitry A. Kazakov 2017-12-18 22:47 ` Randy Brukardt 2017-12-19 1:01 ` Jere 0 siblings, 2 replies; 46+ messages in thread From: Dmitry A. Kazakov @ 2017-12-17 15:39 UTC (permalink / raw) On 2017-12-17 16:26, Jere wrote: > my assertion is that: > > subtype Thing is Core_Pkg.Thing; > > procedure Do_Something(The_Thing : in out Thing) > renames Core_Pkg.Do_Something; > > > is easier to both maintain and read than: > > type Thing is new Core_Pkg.Thing with null record; > > procedure Do_Something(The_Thing : in out Thing); But these are two semantically different concepts. Ada's subtype declares an equivalent type [it inherits everything from and exports everything to the base]. Ada's new tagged type declares a new instance of a class. It only inherits. I don't understand how can you exchange one for another. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-17 15:39 ` Dmitry A. Kazakov @ 2017-12-18 22:47 ` Randy Brukardt 2017-12-19 1:22 ` Jere 2017-12-19 1:01 ` Jere 1 sibling, 1 reply; 46+ messages in thread From: Randy Brukardt @ 2017-12-18 22:47 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:p16332$1rfb$1@gioia.aioe.org... > On 2017-12-17 16:26, Jere wrote: > >> my assertion is that: >> >> subtype Thing is Core_Pkg.Thing; >> >> procedure Do_Something(The_Thing : in out Thing) >> renames Core_Pkg.Do_Something; >> is easier to both maintain and read than: >> >> type Thing is new Core_Pkg.Thing with null record; >> procedure Do_Something(The_Thing : in out Thing); > > But these are two semantically different concepts. Ada's subtype declares > an equivalent type [it inherits everything from and exports everything to > the base]. Ada's new tagged type declares a new instance of a class. It > only inherits. > > I don't understand how can you exchange one for another. You can't really; they're very different concepts. The OP is showing a confusion, because the renames he wants is perfectly legal, assuming proper visibility. And if the items in question are private, then he is trying to make a privacy leak -- which the language will not make easy for obvious reasons. Randy/ ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-18 22:47 ` Randy Brukardt @ 2017-12-19 1:22 ` Jere 2017-12-19 23:16 ` Randy Brukardt 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-19 1:22 UTC (permalink / raw) On Monday, December 18, 2017 at 5:47:51 PM UTC-5, Randy Brukardt wrote: > "Dmitry A. Kazakov" wrote in message > > On 2017-12-17 16:26, Jere wrote: > > > >> my assertion is that: > >> > >> subtype Thing is Core_Pkg.Thing; > >> > >> procedure Do_Something(The_Thing : in out Thing) > >> renames Core_Pkg.Do_Something; > >> is easier to both maintain and read than: > >> > >> type Thing is new Core_Pkg.Thing with null record; > >> procedure Do_Something(The_Thing : in out Thing); > > > > But these are two semantically different concepts. Ada's subtype declares > > an equivalent type [it inherits everything from and exports everything to > > the base]. Ada's new tagged type declares a new instance of a class. It > > only inherits. > > > > I don't understand how can you exchange one for another. > > You can't really; they're very different concepts. The OP is showing a > confusion, because the renames he wants is perfectly legal, assuming proper > visibility. And if the items in question are private, then he is trying to > make a privacy leak -- which the language will not make easy for obvious > reasons. > > Randy/ I'm not really trying to make a privacy leak on purpose. I'm just trying to provide a simpler interface to a much more complex and dangerous generic so that someone doesn't accidentally use something they shouldn't. Any privacy leaks are not intentional. I was just asking a question. Using either extension, derivations, or composition all seemed very heavy handed for just wanting to mimic the same specification as another generic. Subtypes and renames expressed exactly the relationship I wanted, but the only thing I couldn't do was hide a deallocation operation that should never be called directly (it was an input to the base generic). That one items is what got me to this question. I wanted to see if there was a way to keep the subtype/rename method while hiding the operation and the answer looks to be no. But I wasn't sitting around twiddling my fingers looking for ways to break Ada privacy in the process. I just wanted to understand if there was a way and if not, why. That's all, nothing nefarious on my part, at least not intentionally. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-19 1:22 ` Jere @ 2017-12-19 23:16 ` Randy Brukardt 0 siblings, 0 replies; 46+ messages in thread From: Randy Brukardt @ 2017-12-19 23:16 UTC (permalink / raw) "Jere" <jhb.chat@gmail.com> wrote in message news:c29c753e-18e9-475b-9a28-a19aa697ea2f@googlegroups.com... ... > Using > either extension, derivations, or composition all seemed very heavy handed > for just wanting to mimic the same specification as another generic. Fair enough, but it seems like a bizarre thing to do. If I start getting a generic design that is too complex to use easily, I'm likely to toss the entire thing in the junk and do something else. (And exposing access types is almost always a bad idea, because you force the client to do memory management, eliminating the possibilities that they have of using containers or stack allocation to avoid it altogether.) Also note that you'll end up with visibility problems if both packages end up used in a program (which seems likely), as the operations in each will conflict. Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-17 15:39 ` Dmitry A. Kazakov 2017-12-18 22:47 ` Randy Brukardt @ 2017-12-19 1:01 ` Jere 2017-12-19 9:08 ` Dmitry A. Kazakov 2017-12-19 19:10 ` Stephen Leake 1 sibling, 2 replies; 46+ messages in thread From: Jere @ 2017-12-19 1:01 UTC (permalink / raw) On Sunday, December 17, 2017 at 10:39:17 AM UTC-5, Dmitry A. Kazakov wrote: > On 2017-12-17 16:26, Jere wrote: > > > my assertion is that: > > > > subtype Thing is Core_Pkg.Thing; > > > > procedure Do_Something(The_Thing : in out Thing) > > renames Core_Pkg.Do_Something; > > > > > > is easier to both maintain and read than: > > > > type Thing is new Core_Pkg.Thing with null record; > > > > procedure Do_Something(The_Thing : in out Thing); > > But these are two semantically different concepts. Ada's subtype > declares an equivalent type [it inherits everything from and exports > everything to the base]. Ada's new tagged type declares a new instance > of a class. It only inherits. > > I don't understand how can you exchange one for another. > > -- > Regards, > Dmitry A. Kazakov > http://www.dmitry-kazakov.de I don't want to exchange one for the other. I have a package that I want to provide default arguments to privately but maintain the same exact type/operation specification. Subtyping seems more correct than inheritance in this case. I'm not trying to define a new type or an extension of a type. I just want provide a simpler interface to a much more complex generic while hiding part of that so the user doesn't accidentally do something they shouldn't. Something like: generic type Item_Type(<>); type Item_Access is access Item_type; with procedure Deallocation(Ref : in out Item_Access); package Sledgehammer is <types> <operations> private <implementation> end Sledgehammer; This would be used in maybe 5% or less of the code base and only when absolutely necessary. I want to convert it to: generic type Item_Type(<>) is limited private; package Nicer_Package is type Item_Access is access Item_Type; <same types> <same operations> private procedure Deallocate is new Ada.Unchecked_Deallocation (Item_Type,Item_Access); package Implementation is new Sledgehammer (Item_Type => Item_Type, Item_Access => Item_Access, Deallocation => Deallocate); <implementation> end Nicer_Package; Since all I am doing is automating the access type and the deallocation operation, I don't think a new type is really the right design. Additionally, I don't want to expose the deallocation operation as it should never be called directly. Based on earlier conversion from Jeff, it looks like composition is my best bet since I cannot do it via subtyping and renames. I was just hoping there was a way I could do it without adding so much extra stuff to read and maintain. I don't like decreasing readability like that. If I am willing to expose the deallocation operation, then I can just use subtype and renames (which make more sense to me in this case) but that's the tradeoff. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-19 1:01 ` Jere @ 2017-12-19 9:08 ` Dmitry A. Kazakov 2017-12-19 13:08 ` Jere 2017-12-19 19:10 ` Stephen Leake 1 sibling, 1 reply; 46+ messages in thread From: Dmitry A. Kazakov @ 2017-12-19 9:08 UTC (permalink / raw) On 2017-12-19 02:01, Jere wrote: > On Sunday, December 17, 2017 at 10:39:17 AM UTC-5, Dmitry A. Kazakov wrote: >> On 2017-12-17 16:26, Jere wrote: >> > Something like: > > generic > type Item_Type(<>); > type Item_Access is access Item_type; > with procedure Deallocation(Ref : in out Item_Access); > package Sledgehammer is > <types> > <operations> > private > <implementation> > end Sledgehammer; > > This would be used in maybe 5% or less of the code base and only > when absolutely necessary. I want to convert it to: > > generic > type Item_Type(<>) is limited private; > package Nicer_Package is > type Item_Access is access Item_Type; > <same types> > <same operations> > private > procedure Deallocate is new Ada.Unchecked_Deallocation > (Item_Type,Item_Access); > > package Implementation is new Sledgehammer > (Item_Type => Item_Type, > Item_Access => Item_Access, > Deallocation => Deallocate); > > <implementation> > end Nicer_Package; > > Since all I am doing is automating the access type and > the deallocation operation, I don't think a new type > is really the right design. Additionally, I don't want > to expose the deallocation operation as it should never > be called directly. How do you create objects? There are two approaches: 1. Explicit new, implicit deallocate. This works only with containers, which should know the access type and the deallocator. 2. Factory (a Create call), implicit deallocate. This requires reference counting or custom GC pool. P.S., declaring an access type in the public part of a generic is suspicious for bad design. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-19 9:08 ` Dmitry A. Kazakov @ 2017-12-19 13:08 ` Jere 2017-12-19 13:27 ` Dmitry A. Kazakov 0 siblings, 1 reply; 46+ messages in thread From: Jere @ 2017-12-19 13:08 UTC (permalink / raw) On Tuesday, December 19, 2017 at 4:08:46 AM UTC-5, Dmitry A. Kazakov wrote: > On 2017-12-19 02:01, Jere wrote: > > On Sunday, December 17, 2017 at 10:39:17 AM UTC-5, Dmitry A. Kazakov wrote: > >> On 2017-12-17 16:26, Jere wrote: > >> > > Something like: > > > > generic > > type Item_Type(<>); > > type Item_Access is access Item_type; > > with procedure Deallocation(Ref : in out Item_Access); > > package Sledgehammer is > > <types> > > <operations> > > private > > <implementation> > > end Sledgehammer; > > > > This would be used in maybe 5% or less of the code base and only > > when absolutely necessary. I want to convert it to: > > > > generic > > type Item_Type(<>) is limited private; > > package Nicer_Package is > > type Item_Access is access Item_Type; > > <same types> > > <same operations> > > private > > procedure Deallocate is new Ada.Unchecked_Deallocation > > (Item_Type,Item_Access); > > > > package Implementation is new Sledgehammer > > (Item_Type => Item_Type, > > Item_Access => Item_Access, > > Deallocation => Deallocate); > > > > <implementation> > > end Nicer_Package; > > > > Since all I am doing is automating the access type and > > the deallocation operation, I don't think a new type > > is really the right design. Additionally, I don't want > > to expose the deallocation operation as it should never > > be called directly. > > How do you create objects? Explicit. The client does. It's mostly due to the need for of the incomplete type. I can't make or manage objects of type Item_Type, so the client has to allocate. > > There are two approaches: > > 1. Explicit new, implicit deallocate. This works only with containers, > which should know the access type and the deallocator. > > 2. Factory (a Create call), implicit deallocate. This requires reference > counting or custom GC pool. > > P.S., declaring an access type in the public part of a generic is > suspicious for bad design. > Again, it is only for basically to keep the client from having to specify in 90-95% of the situations where they don't really need it. The type is never used to create variables. In the more complex generic, I make the client specify instead, but the simpler one is just for quick utility and hopefully lack of exposure to the deallocation routine. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-19 13:08 ` Jere @ 2017-12-19 13:27 ` Dmitry A. Kazakov 0 siblings, 0 replies; 46+ messages in thread From: Dmitry A. Kazakov @ 2017-12-19 13:27 UTC (permalink / raw) On 2017-12-19 14:08, Jere wrote: >> How do you create objects? > > Explicit. The client does. It's mostly due to the need > for of the incomplete type. I can't make or manage objects > of type Item_Type, so the client has to allocate. How do you deallocate it? I usually use reference counting. The clients use a handle type which is controlled. The handle references a limited controlled type. Ideally the clients do not see the target type and use handles only. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-19 1:01 ` Jere 2017-12-19 9:08 ` Dmitry A. Kazakov @ 2017-12-19 19:10 ` Stephen Leake 1 sibling, 0 replies; 46+ messages in thread From: Stephen Leake @ 2017-12-19 19:10 UTC (permalink / raw) On Monday, December 18, 2017 at 7:01:49 PM UTC-6, Jere wrote: > On Sunday, December 17, 2017 at 10:39:17 AM UTC-5, Dmitry A. Kazakov wrote: > > On 2017-12-17 16:26, Jere wrote: > > > > > my assertion is that: > > > > > > subtype Thing is Core_Pkg.Thing; > > > > > > procedure Do_Something(The_Thing : in out Thing) > > > renames Core_Pkg.Do_Something; > > > > > > > > > is easier to both maintain and read than: > > > > > > type Thing is new Core_Pkg.Thing with null record; > > > > > > procedure Do_Something(The_Thing : in out Thing); > > > > But these are two semantically different concepts. Ada's subtype > > declares an equivalent type [it inherits everything from and exports > > everything to the base]. Ada's new tagged type declares a new instance > > of a class. It only inherits. > > > > I don't understand how can you exchange one for another. > > > > -- > > Regards, > > Dmitry A. Kazakov > > http://www.dmitry-kazakov.de > > I don't want to exchange one for the other. I have a package that I want > to provide default arguments to privately but maintain the same exact > type/operation specification. Subtyping seems more correct than > inheritance in this case. I'm not trying to define a new type or an > extension of a type. I just want provide a simpler interface to a > much more complex generic while hiding part of that so the user doesn't > accidentally do something they shouldn't. > > Something like: > > generic > type Item_Type(<>); > type Item_Access is access Item_type; > with procedure Deallocation(Ref : in out Item_Access); > package Sledgehammer is > <types> > <operations> > private > <implementation> > end Sledgehammer; > > This would be used in maybe 5% or less of the code base and only > when absolutely necessary. I want to convert it to: > > generic > type Item_Type(<>) is limited private; > package Nicer_Package is > type Item_Access is access Item_Type; > <same types> > <same operations> > private > procedure Deallocate is new Ada.Unchecked_Deallocation > (Item_Type,Item_Access); > > package Implementation is new Sledgehammer > (Item_Type => Item_Type, > Item_Access => Item_Access, > Deallocation => Deallocate); > > <implementation> > end Nicer_Package; I had a pattern like that in my original SAL library. I provided "Aux" generics to do the helper instantiations in the simple cases, so the typical use case was: package My_List_Aux is new Sledgehammer_Aux (Item_Type); package My_Lists is new Sledgehammer (Item_Type, My_List_Aux.Item_Access, My_List_Aux.Deallocate); I found that to be a good compromise. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-03 2:14 Full view of a private partial view cannot be a subtype Jere 2017-12-03 12:01 ` Jeffrey R. Carter 2017-12-04 20:49 ` Randy Brukardt @ 2017-12-18 20:45 ` Stephen Leake 2017-12-18 22:54 ` Randy Brukardt 2017-12-19 1:08 ` Jere 2 siblings, 2 replies; 46+ messages in thread From: Stephen Leake @ 2017-12-18 20:45 UTC (permalink / raw) On Saturday, December 2, 2017 at 8:14:50 PM UTC-6, Jere wrote: > There are times where in another package I want to > subtype Base.Instance and do renames of the operations in order > to bring them all into scope (or whatever the correct term is): > > package New_Type1 is > subtype Instance is Base.Instance; > procedure Operation(Object : in out Instance); > > private > > procedure Operation(Object : in out Instance) renames Base.Operation; > end New_Type1; Why subtype? why not a derived type? why do you need a new name with the same operations? > (NOTE: is there a better way to do this?) Yes, use a derived type: type Instance is new Base.Instance; Since Base.Instance is not abstract, you don't need to do anything else; all the operations are inherited. Optionally, you can override some operations to change what they do. > So I guess my question is two part: > > 1. Is there a way to make the full view of a private type > a subtype when the partial view is not a subtype? Or am > I forced to derive a new type? > > 2. If it isn't possible, are there any language reasons for > why that must be so? Would making a full view of a type > actually a subtype under the hood break something? subtypes just declare a new name with new constraints; derived types declare a new type. So you'd be lying to the clients of the package; that always causes problems. -- Stephe ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-18 20:45 ` Stephen Leake @ 2017-12-18 22:54 ` Randy Brukardt 2017-12-19 1:08 ` Jere 1 sibling, 0 replies; 46+ messages in thread From: Randy Brukardt @ 2017-12-18 22:54 UTC (permalink / raw) "Stephen Leake" <stephen_leake@stephe-leake.org> wrote in message news:ceef5c1e-b80b-42c7-9d11-12e52dc6c266@googlegroups.com... > On Saturday, December 2, 2017 at 8:14:50 PM UTC-6, Jere wrote: >> There are times where in another package I want to >> subtype Base.Instance and do renames of the operations in order >> to bring them all into scope (or whatever the correct term is): >> >> package New_Type1 is >> subtype Instance is Base.Instance; >> procedure Operation(Object : in out Instance); >> >> private >> >> procedure Operation(Object : in out Instance) renames >> Base.Operation; >> end New_Type1; > > Why subtype? why not a derived type? why do you need a new name with the > same operations? > >> (NOTE: is there a better way to do this?) > > Yes, use a derived type: > > type Instance is new Base.Instance; > > Since Base.Instance is not abstract, you don't need to do anything else; > all the operations are inherited. > > Optionally, you can override some operations to change what they do. > >> So I guess my question is two part: >> >> 1. Is there a way to make the full view of a private type >> a subtype when the partial view is not a subtype? Or am >> I forced to derive a new type? >> >> 2. If it isn't possible, are there any language reasons for >> why that must be so? Would making a full view of a type >> actually a subtype under the hood break something? > > subtypes just declare a new name with new constraints; derived types > declare a new type. So you'd be lying to the clients of the package; > that always causes problems. Right. The type model of Ada is that every named type is disjoint. For the perspective of a client, a private type is different than any other type that it could know about. OTOH, a subtype is the *same* type as some other type. So you would have view-dependent typing (depending on where you are in the program, it would differ as to whether whether the types are distinct or the same). We have a saying for such thing in the ARG: "that way lies madness!". The only other way to make it work would be to abandon strict privacy, and have the semantics of a private type depend on the completion. That would be totally contrary to the goals of Ada, so that's not a serious option, either. So this is not happening, it does not make semantic sense. Randy. ^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: Full view of a private partial view cannot be a subtype 2017-12-18 20:45 ` Stephen Leake 2017-12-18 22:54 ` Randy Brukardt @ 2017-12-19 1:08 ` Jere 1 sibling, 0 replies; 46+ messages in thread From: Jere @ 2017-12-19 1:08 UTC (permalink / raw) On Monday, December 18, 2017 at 3:45:31 PM UTC-5, Stephen Leake wrote: > On Saturday, December 2, 2017 at 8:14:50 PM UTC-6, Jere wrote: > > There are times where in another package I want to > > subtype Base.Instance and do renames of the operations in order > > to bring them all into scope (or whatever the correct term is): > > > > package New_Type1 is > > subtype Instance is Base.Instance; > > procedure Operation(Object : in out Instance); > > > > private > > > > procedure Operation(Object : in out Instance) renames Base.Operation; > > end New_Type1; > > Why subtype? why not a derived type? why do you need a new name with the same operations? It's not a new name...it's actually the same name in a different package. I am basically trying to mimic a much more complex package with a simpler one. They would have the same typenames and operations. I didn't really want to create a new type, just provide a simpler interface to an existing one while hiding one particularly dangerous detail if I could. ^ permalink raw reply [flat|nested] 46+ messages in thread
end of thread, other threads:[~2017-12-19 23:16 UTC | newest] Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-12-03 2:14 Full view of a private partial view cannot be a subtype Jere 2017-12-03 12:01 ` Jeffrey R. Carter 2017-12-03 13:33 ` Jere 2017-12-03 14:34 ` Jeffrey R. Carter 2017-12-03 17:44 ` Robert Eachus 2017-12-03 18:50 ` Simon Wright 2017-12-03 22:10 ` Robert Eachus 2017-12-03 19:03 ` Jeffrey R. Carter 2017-12-03 22:23 ` Jere 2017-12-04 8:25 ` Dmitry A. Kazakov 2017-12-04 18:04 ` Jeffrey R. Carter 2017-12-04 20:41 ` Jere 2017-12-04 21:48 ` Jeffrey R. Carter 2017-12-05 8:20 ` Dmitry A. Kazakov 2017-12-05 18:16 ` Jeffrey R. Carter 2017-12-05 20:39 ` Dmitry A. Kazakov 2017-12-05 21:38 ` Jeffrey R. Carter 2017-12-05 12:35 ` Jere 2017-12-05 18:40 ` Jeffrey R. Carter 2017-12-06 12:54 ` Jere 2017-12-06 18:03 ` Jeffrey R. Carter 2017-12-05 20:22 ` Randy Brukardt 2017-12-05 15:27 ` Shark8 2017-12-05 18:50 ` Jeffrey R. Carter 2017-12-05 20:59 ` Randy Brukardt 2017-12-05 22:43 ` Shark8 2017-12-07 0:52 ` Randy Brukardt 2017-12-05 20:16 ` Randy Brukardt 2017-12-05 21:29 ` Jeffrey R. Carter 2017-12-07 0:04 ` Randy Brukardt 2017-12-04 20:49 ` Randy Brukardt 2017-12-05 12:56 ` Jere 2017-12-05 20:12 ` Randy Brukardt 2017-12-17 15:26 ` Jere 2017-12-17 15:39 ` Dmitry A. Kazakov 2017-12-18 22:47 ` Randy Brukardt 2017-12-19 1:22 ` Jere 2017-12-19 23:16 ` Randy Brukardt 2017-12-19 1:01 ` Jere 2017-12-19 9:08 ` Dmitry A. Kazakov 2017-12-19 13:08 ` Jere 2017-12-19 13:27 ` Dmitry A. Kazakov 2017-12-19 19:10 ` Stephen Leake 2017-12-18 20:45 ` Stephen Leake 2017-12-18 22:54 ` Randy Brukardt 2017-12-19 1:08 ` Jere
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox