* Derived private interface @ 2011-07-05 3:14 Rego, P. 2011-07-05 5:10 ` AdaMagica 0 siblings, 1 reply; 63+ messages in thread From: Rego, P. @ 2011-07-05 3:14 UTC (permalink / raw) Hi people, I'm just trying to implement a private type derived from an interface, but possibly doing wrong. So, in my code: type My_Interface is interface; procedure Doit (O : access My_Interface) is abstract; type Derived_Class is new My_Interface with private; [...] private type Derived_Class is tagged record First_Record : Integer; end record; so when I try to compile, I get these errors: 'interface "My_Interface" not implemented by full type (RM-2005 7.3 (7.3/2))' 'full view of private extension must be an extension' Does anyone know how can I fix it? ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-05 3:14 Derived private interface Rego, P. @ 2011-07-05 5:10 ` AdaMagica 2011-07-06 2:24 ` Rego, P. 2011-07-06 4:34 ` AdaMagica 0 siblings, 2 replies; 63+ messages in thread From: AdaMagica @ 2011-07-05 5:10 UTC (permalink / raw) type My_Interface is interface; procedure Doit (O : access My_Interface) is abstract; type Derived_Class is new My_Interface with private; procedure Doit (X: access Derived_Class); [...] private type Derived_Class is new My_Interface with record First_Record : Integer; end record; ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-05 5:10 ` AdaMagica @ 2011-07-06 2:24 ` Rego, P. 2011-07-06 4:34 ` AdaMagica 1 sibling, 0 replies; 63+ messages in thread From: Rego, P. @ 2011-07-06 2:24 UTC (permalink / raw) Thanks, it worked! :-) ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-05 5:10 ` AdaMagica 2011-07-06 2:24 ` Rego, P. @ 2011-07-06 4:34 ` AdaMagica 2011-07-06 7:55 ` Georg Bauhaus 1 sibling, 1 reply; 63+ messages in thread From: AdaMagica @ 2011-07-06 4:34 UTC (permalink / raw) I should have written overriding procedure Doit (X: access Derived_Class); ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 4:34 ` AdaMagica @ 2011-07-06 7:55 ` Georg Bauhaus 2011-07-06 8:30 ` AdaMagica ` (3 more replies) 0 siblings, 4 replies; 63+ messages in thread From: Georg Bauhaus @ 2011-07-06 7:55 UTC (permalink / raw) On 7/6/11 6:34 AM, AdaMagica wrote: > I should have written > > overriding procedure Doit (X: access Derived_Class); Instead of sprinkling the program with overriding indicators, shouldn't it be normal for a compiler to detect the status of a subprogram WRT overriding? (It is, I think, and not just in Ada.) Consequently, programmers would mark the opposite case. They'd write "not overriding" only if a subprogram is really intended to not be overriding. Premises: - A subprogram is an overriding subprogram in most cases. + I.e., a subprogram following a type declaration is usually intended to override. Here, "usually" refers to OOD being ubiquitous. - Idiomatic use will suggest to place non-overriding subprograms in nested packages (factories, for example). - Compilers will warn in any case whenever they detect a subprogram that looks suspicious. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 7:55 ` Georg Bauhaus @ 2011-07-06 8:30 ` AdaMagica 2011-07-06 12:59 ` Georg Bauhaus 2011-07-07 10:37 ` Stephen Leake 2011-07-06 15:06 ` Adam Beneschan ` (2 subsequent siblings) 3 siblings, 2 replies; 63+ messages in thread From: AdaMagica @ 2011-07-06 8:30 UTC (permalink / raw) On 6 Jul., 09:55, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: > On 7/6/11 6:34 AM, AdaMagica wrote: > > > I should have written > > > overriding procedure Doit (X: access Derived_Class); > > Instead of sprinkling the program with overriding indicators, > shouldn't it be normal for a compiler to detect the status of > a subprogram WRT overriding? (It is, I think, and not just in > Ada.) Consequently, programmers would mark the opposite case. > They'd write "not overriding" only if a subprogram is really > intended to not be overriding. OK, the compiler knows what it is - but the programmer perhaps doesn't. It is a hint for the compiler to check the programmer's intention. overriding: the compiler complains - oops, did I misspell the name? non overriding: the compiler complains - oops, I thought there was an inherited version. In both cases, if the compiler suddenly complains when before everything was OK, something in the hierarchy below the actual type must have changed. Without those keywords, you will never be informed and will spend hours or days debugging. > Premises: > - A subprogram is an overriding subprogram in most cases. > + I.e., a subprogram following a type declaration is usually > intended to override. Here, "usually" refers to OOD > being ubiquitous. Really? > - Idiomatic use will suggest to place non-overriding subprograms > in nested packages (factories, for example). No, a non-overriding operation may well be primitive, so cannot be in a nested scope. > - Compilers will warn in any case whenever they detect > a subprogram that looks suspicious. When is something suspicious for the (mind-reading) compiler? ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 8:30 ` AdaMagica @ 2011-07-06 12:59 ` Georg Bauhaus 2011-07-06 13:23 ` AdaMagica ` (2 more replies) 2011-07-07 10:37 ` Stephen Leake 1 sibling, 3 replies; 63+ messages in thread From: Georg Bauhaus @ 2011-07-06 12:59 UTC (permalink / raw) On 06.07.11 10:30, AdaMagica wrote: > On 6 Jul., 09:55, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: >> On 7/6/11 6:34 AM, AdaMagica wrote: >> >>> I should have written >> >>> overriding procedure Doit (X: access Derived_Class); >> > In both cases, if the compiler suddenly complains when before > everything was OK, something in the hierarchy below the actual type > must have changed. Without those keywords, you will never be informed > and will spend hours or days debugging. Besides these cases, there are other cases that will make the compiler complain only if a programmer has placed overriding_indicators. With good reason, from his or her point of view. If a programmer's intent has been to express overriding status, but, when trying to do so, he or she did not understand the full set of rules that restrict the set of permissible places for overriding_indicator, the compiler's complaint may generate anger more than anything else. And maybe that anger is justified. That is, in this programming situation involving non-overriding operations, the [not] overriding_indicator does not entail measures against the effects of typos (the feature's purpose as stated in the RM). But it may well create confusion. Even when some lengthy formal exegesis will permit putting the blame on the programmer, this does not seem helpful. I can't think this has been an intent, either. The LRM rules regulating overriding_indicator seem to have been derived form Ada's O-O logic and visibility. Not so much from the more general programming situation where any indicators would instead cater to programmers' intentions, IMHO. overriding_indicators are all logical and such, and I'll accept it if they cannot be designed any better. But somehow I like package C4 below a lot more than I like the others. (The error message at L.26 and L.37, taken together, are---per se---confusing, aren't they?) Example: Compilation started at Wed Jul 6 11:13:55 gnatmake -gnatwa -gnatvf -gnatl ovrd.ads gcc -c -gnatwa -gnatvf -gnatl ovrd.ads GNAT 4.7.0 20110610 (experimental) Copyright 1992-2011, Free Software Foundation, Inc. Compiling: ovrd.ads (source file time stamp: 2011-07-06 11:13:47) 1. package Ovrd is 2. 3. package P1 is 4. 5. type T1 is abstract tagged private; 6. procedure Op (X : in out T1) is abstract; 7. 8. private 9. type T1 is abstract tagged null record; 10. end P1; 11. 12. package P2 is 13. 14. type T2 is new P1.T1 with private; 15. procedure Oops (X : in out T2); 16. -- typo, possibly not caught by soundex algorithm etc, but... 17. private 18. type T2 is new P1.T1 with null record; | >>> type must be declared abstract or "Op" overridden >>> "Op" has been inherited at line 14 >>> "Op" has been inherited from subprogram at line 6 19. end P2; 20. 21. 22. package C1 is 23. 24. type T1 is private; 25. not overriding -- E! `Op` overrides invisibly (in private part) 26. procedure Op (X : in out T1); | >>> subprogram "Op" overrides inherited operation at line 29 27. 28. private 29. type T1 is new P1.T1 with null record; 30. end C1; 31. 32. 33. package C2 is 34. 35. type T1 is private; 36. overriding -- E! Overriding? Yes, but privately 37. procedure Op (X : in out T1); | >>> subprogram "Op" is not overriding 38. 39. private 40. type T1 is new P1.T1 with null record; 41. end C2; 42. 43. 44. package C3 is 45. 46. type T1 is private; 47. not overriding -- OK, not overriding in any place 48. procedure Op (X : in out T1); 49. 50. private 51. type T1 is null record; 52. end C3; 53. 54. 55. package C4 is 56. 57. type T1 is private; 58. -- Overriding status is not known. Should we care 59. -- in this case, for a type that is simply private? 60. procedure Op (X : in out T1); 61. 62. private 63. type T1 is new P1.T1 with null record; 64. end C4; 65. 66. 67. package C5 is 68. 69. type T1 is private; 70. -- No more `Op` 71. 72. private 73. type T1 is new P1.T1 with null record; 74. overriding -- correct, overriding at this place 75. procedure Op (X : in out T1); 76. end C5; 77. 78. end Ovrd; 78 lines: 5 errors gnatmake: "ovrd.ads" compilation error Compilation exited abnormally with code 4 at Wed Jul 6 11:13:55 ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 12:59 ` Georg Bauhaus @ 2011-07-06 13:23 ` AdaMagica 2011-07-06 19:06 ` Randy Brukardt 2011-07-06 13:28 ` Simon Wright 2011-07-06 19:45 ` Randy Brukardt 2 siblings, 1 reply; 63+ messages in thread From: AdaMagica @ 2011-07-06 13:23 UTC (permalink / raw) I guess this has to be based on visibility to prevent privacy breaking. In these cases where overriding indicators are illegal in the spec, they can be applied in the body. Note that the RM does not make any statement whether they shall appear at the spec, body, or both. I think a general idiom should be: use them at both places as long as is legal. Thus you provide the most information to the compiler and future readers of the code. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 13:23 ` AdaMagica @ 2011-07-06 19:06 ` Randy Brukardt 0 siblings, 0 replies; 63+ messages in thread From: Randy Brukardt @ 2011-07-06 19:06 UTC (permalink / raw) "AdaMagica" <christ-usch.grein@t-online.de> wrote in message news:7c515c1d-d170-4cd2-8702-6532e09d6f42@y24g2000yqb.googlegroups.com... >I guess this has to be based on visibility to prevent privacy > breaking. In these cases where overriding indicators are illegal in > the spec, they can be applied in the body. > > Note that the RM does not make any statement whether they shall appear > at the spec, body, or both. Actually, it does. Indicators are not allowed on bodies unless those bodies can act as declarations. > I think a general idiom should be: use them at both places as long as > is legal. Thus you provide the most information to the compiler and > future readers of the code. You can't do that in general (specifically, for protected subprograms) and that is intentional. The intent was that the indicators be provided only once (on the spec, or on a body acting as a spec). Beyond that, there was an allowance to put indicators on bodies when they were omitted from the spec; but there was never any intent that indicators would be *repeated* on bodies. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 12:59 ` Georg Bauhaus 2011-07-06 13:23 ` AdaMagica @ 2011-07-06 13:28 ` Simon Wright 2011-07-06 19:45 ` Randy Brukardt 2 siblings, 0 replies; 63+ messages in thread From: Simon Wright @ 2011-07-06 13:28 UTC (permalink / raw) Georg Bauhaus <rm.dash-bauhaus@futureapps.de> writes: > (The error message at L.26 and L.37, taken together, are---per > se---confusing, aren't they?) > 22. package C1 is > 23. > 24. type T1 is private; > 25. not overriding -- E! `Op` overrides invisibly (in private part) > 26. procedure Op (X : in out T1); > | > >>> subprogram "Op" overrides inherited operation at line 29 > > 27. > 28. private > 29. type T1 is new P1.T1 with null record; > 30. end C1; > 31. > 32. > 33. package C2 is > 34. > 35. type T1 is private; > 36. overriding -- E! Overriding? Yes, but privately > 37. procedure Op (X : in out T1); > | > >>> subprogram "Op" is not overriding > > 38. > 39. private > 40. type T1 is new P1.T1 with null record; > 41. end C2; The compiler does seem to be a bit confused, but I wonder whether a human reader might not be confused too? It might be good at least to say "type T1 is tagged private;" (though it makes no difference to the reported problem). ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 12:59 ` Georg Bauhaus 2011-07-06 13:23 ` AdaMagica 2011-07-06 13:28 ` Simon Wright @ 2011-07-06 19:45 ` Randy Brukardt 2011-07-06 22:05 ` Georg Bauhaus 2 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-07-06 19:45 UTC (permalink / raw) "Georg Bauhaus" <rm.dash-bauhaus@futureapps.de> wrote in message news:4e145c3a$0$6542$9b4e6d93@newsspool4.arcor-online.net... ... > If a programmer's intent has been to express overriding status, but, when > trying to do so, he or she did not understand the full set of rules > that restrict the set of permissible places for overriding_indicator, > the compiler's complaint may generate anger more than anything else. If the programmer doesn't understand the model of overriding in Ada, they are going to be disappointed. It's better that the compiler complain than silently doing the wrong thing. ... > That is, in this programming situation involving non-overriding > operations, the [not] overriding_indicator does not entail measures > against the effects of typos (the feature's purpose as stated in the RM). I have no idea what you are talking about. The feature definitely prevents problems with the effect of typos; of course, if you use it when there is no overriding going on, you'll have problems. > But it may well create confusion. Even when some lengthy formal > exegesis will permit putting the blame on the programmer, this does > not seem helpful. I can't think this has been an intent, either. If you don't understand what you are doing, you are going to have problems. > The LRM rules regulating overriding_indicator seem to have been > derived form Ada's O-O logic and visibility. What else would it derive from? > Not so much from the > more general programming situation where any indicators would > instead cater to programmers' intentions, IMHO. It corresponds exactly to the programmer's intentions, so long as those intentions are based on the RM definition of overriding and not some other imagined version of the rules. > Example: > ... > 55. package C4 is > 56. > 57. type T1 is private; > 58. -- Overriding status is not known. Should we care > 59. -- in this case, for a type that is simply private? > 60. procedure Op (X : in out T1); > 61. > 62. private > 63. type T1 is new P1.T1 with null record; > 64. end C4; You should not use any indicators in this case, as the type in question is not a derived type (which for this purpose includes type extensions and private extensions). Only derived types inherit anything, so the use of any indicators is wrong/misleading. It should be noted that I had wanted to be able to use "not overriding" everywhere, but I was overruled. The private type demonstrates a serious flaw in Ada that unfortunately we're stuck with. You should not be able to have a routine that is declared in the visible part be overriding in the private part. That should be strictly illegal. (OTOH, it is be OK to override solely in the private part.) Operations that are visible and are inherited should be visibly inherited. The work we've been doing recently with contracts (preconditions, postconditions, and the like) demonstrate this; you will have all sorts of logical problems when the visible contracts on the specification aren't appropriate for those on the overriding. You would be many times better served to visibly inherit the routine (along with the contracts), either by using an interface or by visibly deriving from P1.T1, or to avoid inheritance altogether (by using a record with a component of P1.T1.) Note also that this sort of structure prevents the use of C4.T1 by the client in class-wide operations of P1.T1. That is usually a bad thing (requiring duplication of operations in order to provide equivalent functionality). Sometimes people do this on purpose, in an attempt to "eliminate" operations from an extension. But "eliminating" operations violates all of the theory about OOP, and generally means that a restructuring of your "object" types is needed. To summarize: this is a bad case that shouldn't have been allowed by Ada in the first place -- the problem is with Ada allowing it, not with the use of indicators with it. (You'd have had a better case had you shown examples involving generics. Those caused all of the problems that led us to abandoning the "always use indicators" restriction.) Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 19:45 ` Randy Brukardt @ 2011-07-06 22:05 ` Georg Bauhaus 2011-07-06 23:56 ` Adam Beneschan 0 siblings, 1 reply; 63+ messages in thread From: Georg Bauhaus @ 2011-07-06 22:05 UTC (permalink / raw) On 7/6/11 9:45 PM, Randy Brukardt wrote: > "Georg Bauhaus"<rm.dash-bauhaus@futureapps.de> wrote in message > news:4e145c3a$0$6542$9b4e6d93@newsspool4.arcor-online.net... > ... >> That is, in this programming situation involving non-overriding >> operations, the [not] overriding_indicator does not entail measures >> against the effects of typos (the feature's purpose as stated in the RM). > > I have no idea what you are talking about. (About what you explain later on: that we should avoid overriding_indicators when they create problems...) >> But it may well create confusion. Even when some lengthy formal >> exegesis will permit putting the blame on the programmer, this does >> not seem helpful. I can't think this has been an intent, either. > > If you don't understand what you are doing, you are going to have problems. This topos (of which "Stupid!" seems a possible paraphrase) copies, almost exactly, that of a zealot defending C's flaws, fiercely. ;-) But, seriously, as they reportedly say in ARG circles, almost no one understands Ada. Therefore, if a substantial amount of understanding is necessary in order to use indicators properly, there is something wrong somewhere, IMHO. You have pointed to flaws and alternative solutions, Dmitry has hinted at syntactical means of classifications, I think. >> The LRM rules regulating overriding_indicator seem to have been >> derived form Ada's O-O logic and visibility. > > What else would it derive from? Like in the days that led to Ada: language features should meet a requirement. To establish the requirements, you would, quite naturally, not be taking most input from the language not defined yet. In the case leading to overriding_indicator, the requirements seems to include technicalities with typos in Ada programs ... > It corresponds exactly to the programmer's intentions, so long as those > intentions are based on the RM definition of overriding and not some other > imagined version of the rules. And here's a point: when I use Ada syntax, I like to think that its purpose is to express my intentions with regard to the next thing, which is describing one part of the problem and its solution in Ada. To illustrate, when I write "type" or "procedure" or "loop", then I want the next thing to be a type, a procedure, or a loop. When I write "overriding", I do not influence in any way what the next thing will be (overriding or not), as this is a consequence of language rules. The purpose of syntax should not be to clarify my understanding of the Ada language. Or is a program an exam that tests my understanding of Ada's O-O features? But OK, seen as a use case of syntax, "overriding" as a keyword mirrors "limited" in that there is permission to use and repeat "limited" in a type's definition even when it is limited anyway. I like it. Does "limited" create comparable problems, though? Your comment above is about permissible programmer intentions, if I may say so. Just for contrast, C version: int behavior near INT_MAX corresponds exactly to the programmer's intentions, so long as those intentions are based on the standard's, the compiler's, and the platform's definition (or not) of int and not some other imagined integers. While this is correct, it doesn't prevent the bi-weekly CVE caused by int. > Note also that this sort of structure prevents the use of C4.T1 by the > client in class-wide operations of P1.T1. That is usually a bad thing > (requiring duplication of operations in order to provide equivalent > functionality). Sometimes people do this on purpose, in an attempt to > "eliminate" operations from an extension. But "eliminating" operations > violates all of the theory about OOP, and generally means that a > restructuring of your "object" types is needed. Arguably (and I'm not sure I like the pattern implemented using inheritance), to remove the operations from a type in the visible part (by not making it visibly inheriting) would serve to establish an adapter. I don't see the problem with theory about OOP: - there is then a different type that hides the information that it privately inherits, - clients are prevented form deriving from the visible type. > (You'd have had a better case had you shown examples involving generics. > Those caused all of the problems that led us to abandoning the "always use > indicators" restriction.) So I was right to not even try, based on a gut feeling. :) ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 22:05 ` Georg Bauhaus @ 2011-07-06 23:56 ` Adam Beneschan 2011-07-07 14:09 ` Georg Bauhaus 0 siblings, 1 reply; 63+ messages in thread From: Adam Beneschan @ 2011-07-06 23:56 UTC (permalink / raw) On Jul 6, 3:05 pm, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: > But, seriously, as they reportedly say in ARG circles, almost no one > understands Ada. Therefore, if a substantial amount of understanding > is necessary in order to use indicators properly, there is something > wrong somewhere, IMHO. Either I'm having difficulty following your argument, or you've totally lost the plot. You do not need a lot of understanding to use overriding indicators. If you declare an operation and you intend that this operation replaces (overrides) the same operation for the parent, then add "overriding". If you declare an operation and you intend that it be a NEW operation that did not exist for the parent type, then add "not overriding". Seems simple to me---you don't need a "substantial amount of understanding" for this! If you use one of these indicators, the compiler will then complain if your keyword doesn't match the compiler's concept of whether the declaration is overriding or not. Then you (1) check for typos, (2) check to make sure a new, conflicting operation hasn't been added for an ancestor or progenitor type, or (3) in the complex case where visibility rules cause an inherited operation to disappear, then you'll have to figure out what's going on. Case #3 is the difficult one. But in this case, if you *don't* use the overriding indicator, *then* you need a substantial amount of understanding of the language rules, because the compiler won't check for you; it will assume you know what you're doing. So I think you have it backwards---you need a substantial amount of understanding *NOT* to use overriding indicators. -- Adam ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 23:56 ` Adam Beneschan @ 2011-07-07 14:09 ` Georg Bauhaus 2011-07-07 15:10 ` Adam Beneschan 2011-07-07 15:19 ` Georg Bauhaus 0 siblings, 2 replies; 63+ messages in thread From: Georg Bauhaus @ 2011-07-07 14:09 UTC (permalink / raw) On 07.07.11 01:56, Adam Beneschan wrote: > (3) in the complex case where > visibility rules cause an inherited operation to disappear, then > you'll have to figure out what's going on. Case #3 is the difficult > one. Yes, and either way, I think I'll have to think about complex issues in case #3, with or without indicators, insofar as either issue (backwards or forwards) will point to the same things. Should an issue arise. But point taken, every hint from the compiler is welcome, the better hint wins. I guess I'm uneasy with indicators (which I use) because they purport to solve some problem, but this is just accidental, and ad hoc, and incomplete in several dimensions. Maybe something better is still possible. If indicators are about doing Ada inheritance properly, here is an alternative. (That's likely a bold attempt, but anyway.) Like "overriding", it restricts the language's assistence to just tagged types. Instead of adding all indicators, have the programmer explicitly mention each operation. Let T0 = ({...}, {Op1, ..., OpN}), then deriving T1 from T0 will list all operations {Op1, ..., OpN}. (Tools will help the lazy writer.) For N=2: type T0 is abstract tagged private; procedure Op1 (X : in out T0) is abstract; procedure Op2 (X : in out T0) is abstract; Then, type T1 is abstract new T0 with private; procedure Op1 (X : in out T1) is <>; -- abstract procedure Op2 (X : in out T1); -- overriding procedure Op3 (X : in out T1); -- DC type T2 is new T1 with private; procedure Op1 (X : in out T2); -- overriding procedure Op2 (X : in out T2) is <>; -- inheriting procedure Op3 (X : in out T2); -- overriding procedure Op4 (X : in out T2); -- DC Remove T0's Op2. Then, T1 and T2 will have a dispatching operation that no longer overrides their parent's. Bad? Add Op17 to T1. T2 will become invalid because it does not list Op17. (Fix is to list Op17 using "is <>".) Add Op3 to T0. T1's Op3 then becomes overriding. Bad? Misspelling T2's Op2 renders T2 invalid (because all names of T1 have to be listed and Op2 will not be listed). A call on an object of type T2 cannot "by accident" resolve to a call on T1's. Eiffel has something similar. A class inheriting from other classes will list the features (operations) that it is going to redefine (override). ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-07 14:09 ` Georg Bauhaus @ 2011-07-07 15:10 ` Adam Beneschan 2011-07-08 4:29 ` AdaMagica 2011-07-08 19:12 ` Randy Brukardt 2011-07-07 15:19 ` Georg Bauhaus 1 sibling, 2 replies; 63+ messages in thread From: Adam Beneschan @ 2011-07-07 15:10 UTC (permalink / raw) On Jul 7, 7:09 am, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: > I guess I'm uneasy with indicators (which I use) because they > purport to solve some problem, but this is just accidental, > and ad hoc, and incomplete in several dimensions. Maybe something > better is still possible. I think you're right that this was an ad hoc solution to an unforeseen problem, and that there may have been better ways to do this back in Ada 95 if the team had realized the potential problems. On the other hand, I'm not all that uneasy with it because I realize that if we waited to make sure that everything was perfect, the first version of Ada would have been Ada 2317 or something like that, and we would have been stuck with C until then. Your idea below seems sensible, but it's not backward-compatible; if it were added to the next version of Ada, a lot of legal programs would become illegal, and that's something the designers try to avoid. Perhaps there's a solution involving aspect clauses---since they're new, it would be easier to make them backward-compatible. One idea off the top of my head: type T1 is new T0 with record ... end record with inherit => (Op1, Op3), override => (Op2, Op4); (Aspect specifications don't currently allow lists of identifiers, but this could probably be changed compatibly.) Then the type declaration would be illegal if T0 has a primitive operation that isn't listed in either list, if an operation is listed that isn't a primitive operation of T0, if there is a conflicting declaration for something in the "inherit" list, or there is no overriding declaration for something in the "override" list. This is just a first attempt, and it definitely won't work because it doesn't deal with overloaded names and there are probably problems with private parts. But maybe we could implement your idea and still make things backward compatible: type T1 is new T0 with record ... end record with Georgs_Rules; Then if the "with Georgs_Rules" is present, the operation declarations would have to follow your rules, and if it isn't, they'd follow the old rules. Then GNAT would add an option that would cause the compiler to reject any type extension without this aspect clause. (Somebody else would have to come up with a better name for this aspect.) I'm just brainstorming here; I don't have any idea whether a feature like this would be worthwhile, particularly since it could cause the language rules to become somewhat messy. -- Adam ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-07 15:10 ` Adam Beneschan @ 2011-07-08 4:29 ` AdaMagica 2011-07-08 19:08 ` Randy Brukardt 2011-07-08 19:12 ` Randy Brukardt 1 sibling, 1 reply; 63+ messages in thread From: AdaMagica @ 2011-07-08 4:29 UTC (permalink / raw) 3. package P1 is 5. type T1 is abstract tagged private; 6. procedure Op (X : in out T1) is abstract; 8. private 9. type T1 is abstract tagged null record; 10. end P1; 11. 55. package C4 is 57. type T1 is private; 58. -- Overriding status is not known. Should we care 59. -- in this case, for a type that is simply private? 60. procedure Op (X : in out T1); 62. private 63. type T1 is new P1.T1 with null record; -- But do we have to care here? overriding -- or any other syntax procedure Op (X : in out T1); 64. end C4; All these attempts do not solve the privacy issues of Georg's example repeated here. Would we have to repeat the declaration of Op after the full type declaration when we know whether it is overriding or not? ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-08 4:29 ` AdaMagica @ 2011-07-08 19:08 ` Randy Brukardt 0 siblings, 0 replies; 63+ messages in thread From: Randy Brukardt @ 2011-07-08 19:08 UTC (permalink / raw) "AdaMagica" <christ-usch.grein@t-online.de> wrote in message news:b420bce2-25e9-4500-b31b-60d3c4d7878f@x10g2000vbl.googlegroups.com... ... > All these attempts do not solve the privacy issues of Georg's example > repeated here. Would we have to repeat the declaration of Op after the > full type declaration when we know whether it is overriding or not? That would be best, but of course Ada doesn't allow it. I wonder what new problems would be introduced by such a feature? Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-07 15:10 ` Adam Beneschan 2011-07-08 4:29 ` AdaMagica @ 2011-07-08 19:12 ` Randy Brukardt 1 sibling, 0 replies; 63+ messages in thread From: Randy Brukardt @ 2011-07-08 19:12 UTC (permalink / raw) "Adam Beneschan" <adam@irvine.com> wrote in message news:1c98072b-e5b9-43dd-9fde-f6687086deef@w24g2000yqw.googlegroups.com... ... > (Aspect specifications don't currently allow lists of identifiers, but > this could probably be changed compatibly.) Actually, aspect_specifications allow any syntax that the implementer wants to support - 13.3.1(38/3). To use them portably, of course, you have to stick to the language-defined aspects and syntax, but no surprise there. This was done so that implementers could experiment with ideas like this, the unfinised Global in/global out proposal, and exception contracts, all of which require fancier syntax than is currently defined. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-07 14:09 ` Georg Bauhaus 2011-07-07 15:10 ` Adam Beneschan @ 2011-07-07 15:19 ` Georg Bauhaus 1 sibling, 0 replies; 63+ messages in thread From: Georg Bauhaus @ 2011-07-07 15:19 UTC (permalink / raw) On 07.07.11 16:09, Georg Bauhaus wrote: > Like "overriding", it restricts the language's assistence > to just tagged types. <del>tagged</del> ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 8:30 ` AdaMagica 2011-07-06 12:59 ` Georg Bauhaus @ 2011-07-07 10:37 ` Stephen Leake 2011-07-07 13:18 ` Georg Bauhaus 1 sibling, 1 reply; 63+ messages in thread From: Stephen Leake @ 2011-07-07 10:37 UTC (permalink / raw) AdaMagica <christ-usch.grein@t-online.de> writes: > On 6 Jul., 09:55, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: >> On 7/6/11 6:34 AM, AdaMagica wrote: >> >> > I should have written >> >> > overriding procedure Doit (X: access Derived_Class); >> >> Instead of sprinkling the program with overriding indicators, >> shouldn't it be normal for a compiler to detect the status of >> a subprogram WRT overriding? (It is, I think, and not just in >> Ada.) Consequently, programmers would mark the opposite case. >> They'd write "not overriding" only if a subprogram is really >> intended to not be overriding. > > OK, the compiler knows what it is - but the programmer perhaps > doesn't. It is a hint for the compiler to check the programmer's > intention. > > overriding: the compiler complains - oops, did I misspell the name? > non overriding: the compiler complains - oops, I thought there was an > inherited version. More importantly; oops, I changed the parent, and forgot to change the child; now the compiler warns me. If you don't put 'overriding' on all child operations, they silently become non-overriding when the parent changes. Very Bad Things Happen. -- -- Stephe ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-07 10:37 ` Stephen Leake @ 2011-07-07 13:18 ` Georg Bauhaus 2011-07-08 19:23 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Georg Bauhaus @ 2011-07-07 13:18 UTC (permalink / raw) On 07.07.11 12:37, Stephen Leake wrote: > If you don't put 'overriding' on all child operations, they silently > become non-overriding when the parent changes. Very Bad Things Happen. An indicator "not overriding" will also "help" when one adds a name to a parent that had already been used in a child type and has been duly marked "not overriding" there. It is only an early hint, though. For example, taking care of LSP substitutability is not an immediate consequence of the presence of overriding indicators, but the diagnosis is a start, if not the best IMHO. An indicator "overriding" will also help with c&p errors. For example, when forgetting to adapt parameter profiles to the child type. So this is about typos. What instances of Very Bad Things can be removed with the help of indicators? Some of the Very Bad Things happen mostly when the types do not inherit directly from abstract types or interfaces (as changing ops will then result in compilation errors). This, I think, can be termed The First Bad Thing. Bad things also happen, more generally, whenever some programming error would be prevented simply by adding indicators of suitable sorts that would explain the programmer's intention. But shouldn't this kind of information be covered by "normal" language instead? Or, for an alternative, one might imagine adding a "smart indicator pragma" pragma Fuzzy_Homographs (Threshold => 0.9); This, then, will prevent frequently quoted errors such as Initialse(...) vs Initialize(...). *Without* restricting the compiler's assistance to just tagged types! This, from my point of view, might equip the language with better means of addressing the real issue, which seems to be one of naming. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-07 13:18 ` Georg Bauhaus @ 2011-07-08 19:23 ` Randy Brukardt 2011-07-08 21:41 ` Jeffrey Carter 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-07-08 19:23 UTC (permalink / raw) "Georg Bauhaus" <rm.dash-bauhaus@futureapps.de> wrote in message news:4e15b223$0$6541$9b4e6d93@newsspool4.arcor-online.net... ... > What instances of Very Bad Things can be removed with the > help of indicators? The main one is a routine that did not override when it was expected to. This sort of bug cost us many hours of debugging time in Claw, because when you trace the logic of the program everything seems correct - just the wrong body is being called by dispatching routines and typically you can only figure that out by adding tracing to all of the bodies. Ugh! There are some very subtle visibility-based reasons that a routine will not be overriding, and no programmer can be expected to understand those. In particular, the "sibling inheritance" problem. The "overriding" indicator will at least cause the compiler to complain, and then the programmer can spend his time restructuring his entire system rather than pointlessly debugging. (This particular problem has no workaround; the package structure of the program has to be changed. We tried pretty hard to provide a workaround in Ada 2012, but we couldn't do so compatibly or even with just a compile-time incompatibility, and a runtime incompatibily is unacceptable. Blame interfaces for that - another reason that I hate them. :-) See AI05-0125-1 and the associated minutes for the details, if you care.) Randy. > Some of the Very Bad Things happen mostly when the types > do not inherit directly from abstract types or interfaces (as > changing ops will then result in compilation errors). This, > I think, can be termed The First Bad Thing. > > Bad things also happen, more generally, whenever some programming > error would be prevented simply by adding indicators of suitable > sorts that would explain the programmer's intention. But shouldn't > this kind of information be covered by "normal" language instead? > > Or, for an alternative, one might imagine adding a "smart indicator > pragma" > > pragma Fuzzy_Homographs (Threshold => 0.9); > > This, then, will prevent frequently quoted errors such as > > Initialse(...) vs Initialize(...). > > *Without* restricting the compiler's assistance to just tagged > types! > > This, from my point of view, might equip the language with > better means of addressing the real issue, which seems to > be one of naming. > > > ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-08 19:23 ` Randy Brukardt @ 2011-07-08 21:41 ` Jeffrey Carter 2011-07-09 6:14 ` Dmitry A. Kazakov 2011-07-22 22:59 ` Randy Brukardt 0 siblings, 2 replies; 63+ messages in thread From: Jeffrey Carter @ 2011-07-08 21:41 UTC (permalink / raw) On 07/08/2011 12:23 PM, Randy Brukardt wrote: > > This particular problem has no workaround... I disagree. The use of programming by composition is an effective work around to all the problems introduced by programming by extension. -- Jeff Carter "I don't know why I ever come in here. The flies get the best of everything." Never Give a Sucker an Even Break 102 ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-08 21:41 ` Jeffrey Carter @ 2011-07-09 6:14 ` Dmitry A. Kazakov 2011-07-22 22:59 ` Randy Brukardt 1 sibling, 0 replies; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-07-09 6:14 UTC (permalink / raw) On Fri, 08 Jul 2011 14:41:05 -0700, Jeffrey Carter wrote: > On 07/08/2011 12:23 PM, Randy Brukardt wrote: >> >> This particular problem has no workaround... > > I disagree. The use of programming by composition is an effective work around to > all the problems introduced by programming by extension. Nope, composition would violate the information hiding principle. There is no workarounds to establishing a relationship between two types serving as separate implementations of the *same* abstract concept (except for generics or overloading (static and ad-hoc polymorphism). Both have serious problems especially in the context of large systems design. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-08 21:41 ` Jeffrey Carter 2011-07-09 6:14 ` Dmitry A. Kazakov @ 2011-07-22 22:59 ` Randy Brukardt 2011-07-23 7:30 ` Jeffrey Carter 1 sibling, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-07-22 22:59 UTC (permalink / raw) "Jeffrey Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message news:iv80lh$n8m$1@tornado.tornevall.net... > On 07/08/2011 12:23 PM, Randy Brukardt wrote: >> >> This particular problem has no workaround... > > I disagree. The use of programming by composition is an effective work > around to all the problems introduced by programming by extension. Given that the problem in question is related to dynamic dispatching and has nothing in particular to do with extensions, this is an amazing statement. In Claw, the primary reason for using OOP is for the dispatching -- it ensures that every object has handlers for each of the relevant messages, and also provides useful defaults. And it automatically ensures that the right handler is executed for each object -- no manual binding is required. There is some value to extensions in Claw, but not a lot. OTOH, programming by composition would provide nothing, in that there would be no way to change the handlers for the base type. One could graft some sort of unstructured mechanism on top of the objects (possibly using access-to-subprograms), but this would provide many more opportunities for mistakes (if you forget to set the access-to-subprogram value, the routine might as well not exist). Remember that there are four legs to the OOP stool: strong typing, encapsulation, extension, and dynamic dispatching -- and each of these is orthogonal to the others (shown by the fact that Ada has the first two without even using tagged types, that is OOP). So there is no necessary relationship between extension and dispatching (and working around the one does nothing to solve a problem that mainly depends on the other). Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-22 22:59 ` Randy Brukardt @ 2011-07-23 7:30 ` Jeffrey Carter 2011-07-23 9:29 ` Maciej Sobczak ` (2 more replies) 0 siblings, 3 replies; 63+ messages in thread From: Jeffrey Carter @ 2011-07-23 7:30 UTC (permalink / raw) On 07/22/2011 03:59 PM, Randy Brukardt wrote: > > Given that the problem in question is related to dynamic dispatching and has > nothing in particular to do with extensions, this is an amazing statement. My statement was tongue in cheek, intended to express my dislike for tagged types. Their only value seems to be all the traffic here from people who run into problems trying to use them; this would be a much quieter place without them. Maybe I'm missing something, but it seems to me that all dispatching in Ada is related to extensions. If you have type T is tagged ... procedure P (V : in out T); and you never extend T, then you never get dispatching (in the sense that a call to P results in something other than this P being called). To get dispatching, you have to extend T type T2 is new T with ... overriding procedure P (V : in out T2); Then you can get a single call that sometimes calls P for T and other times P for T2; that's dispatching. I don't know what dispatching means without an extension and an overridden subprogram to dispatch to. > OTOH, programming by composition would provide nothing, in that there would > be no way to change the handlers for the base type. One could graft some > sort of unstructured mechanism on top of the objects (possibly using > access-to-subprograms), but this would provide many more opportunities for > mistakes (if you forget to set the access-to-subprogram value, the routine > might as well not exist). The equivalent of dispatching in programming by composition is a subprogram that contains a case statement that contains calls to other subprograms. No access-to-subprogram values involved. It does the exact same thing as dispatching, except that it's easier to read and understand and doesn't result in large numbers of "what am I doing wrong?" posts to c.l.a. > Remember that there are four legs to the OOP stool: strong typing, > encapsulation, extension, and dynamic dispatching -- and each of these is > orthogonal to the others (shown by the fact that Ada has the first two > without even using tagged types, that is OOP). So there is no necessary > relationship between extension and dispatching (and working around the one > does nothing to solve a problem that mainly depends on the other). Again, I have no idea what dispatching even means in the absence of extension. In Ada, "programming by extension" is achieved by the use of tagged types; it includes dispatching. I have never seen anything implemented using tagged types that could not also be implemented using programming by composition. It follows that if there is a case where tagged types cause a problem, the equivalent solution without tagged types is an effective work around to the problem. Of course, in the case where there is no solution using tagged types, there may also be no solution without using them. -- Jeff Carter "If you think you got a nasty taunting this time, you ain't heard nothing yet!" Monty Python and the Holy Grail 23 ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-23 7:30 ` Jeffrey Carter @ 2011-07-23 9:29 ` Maciej Sobczak 2011-07-23 10:07 ` Dmitry A. Kazakov 2011-07-26 21:04 ` Randy Brukardt 2 siblings, 0 replies; 63+ messages in thread From: Maciej Sobczak @ 2011-07-23 9:29 UTC (permalink / raw) On Jul 23, 9:30 am, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org> wrote: > The equivalent of dispatching in programming by composition is a subprogram that > contains a case statement that contains calls to other subprograms. The whole point of dispatching is to allow the open-closed principle: http://en.wikipedia.org/wiki/Open/closed_principle It has no direct equivalent in programming by composition. > No > access-to-subprogram values involved. Access-to-subprogram is needed to emulate dispatching and provide the open-closed principle at the same time. > It does the exact same thing as > dispatching, except that it's easier to read and understand and doesn't result > in large numbers of "what am I doing wrong?" Without dispatching (and without access-to-subprogram to emulate it) you would have large number of "why should I modify half of my drawing application code just because I have added a rectanlge-with-rounde- corners". -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-23 7:30 ` Jeffrey Carter 2011-07-23 9:29 ` Maciej Sobczak @ 2011-07-23 10:07 ` Dmitry A. Kazakov 2011-07-26 21:04 ` Randy Brukardt 2 siblings, 0 replies; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-07-23 10:07 UTC (permalink / raw) On Sat, 23 Jul 2011 00:30:12 -0700, Jeffrey Carter wrote: > Maybe I'm missing something, but it seems to me that all dispatching in Ada is > related to extensions. Yes, but that is a language design bug (sorry, feature (:-)). There is nothing in the idea of a class of types which would instruct a derived type to add new components, and not to discard existing components, or to provide an absolutely unrelated implementation. Extension is an invention of lazy language designers. > type T2 is new T with ... > > overriding procedure P (V : in out T2); > > Then you can get a single call that sometimes calls P for T and other times P > for T2; that's dispatching. No, it always means the *same* primitive operation P defined on the type T'Class. P for T is defined on T, P for T2 is defined on T2. Neither is defined on T'Class. In Ada you always know which operation is to be called. > I don't know what dispatching means without an > extension and an overridden subprogram to dispatch to. If you mean the implementation of a primitive operation P, then how is it different from other operations? Ada separates interface and implementation. You newer know the implementation without looking into the body(es). > The equivalent of dispatching in programming by composition is a subprogram that > contains a case statement that contains calls to other subprograms. No > access-to-subprogram values involved. It does the exact same thing as > dispatching, except that it's easier to read and understand and doesn't result > in large numbers of "what am I doing wrong?" posts to c.l.a. There is a sufficient difference. The case statement needs an enumeration type (a substitute for the tag type) which should be declared in advance to all future implementations. This means that you have to know all derived types at a very early stage of the project. Certainly you don't want "others =>" in that statement. Furthermore the procedure must "with" all implementations of all derived types. Now you have: 1. Problems with maintenance (fixing the statement and with clauses) 2. You have to ensure the correspondence between the values of the enumeration type and the procedures called in "when This => That (X);". The language cannot help you here. 3. Potential problems with elaboration order (inversed, mutual dependencies). 4. Lack of static check if each "derived" type has a defined body. 5. Lack of abstract types. An abstract type has no instances, but may have implementations. I.e. it appear in the switch. But you cannot compose abstract components. Once abstract always abstract. And finally, it does not change anything semantically. Whatever problem (substitutability issues / LSP) the programmer might have with tagged types, he will under composition. > In Ada, "programming by extension" is achieved by the use of tagged types; it > includes dispatching. I have never seen anything implemented using tagged types > that could not also be implemented using programming by composition. It follows > that if there is a case where tagged types cause a problem, the equivalent > solution without tagged types is an effective work around to the problem. > > Of course, in the case where there is no solution using tagged types, there may > also be no solution without using them. An argument to Turing-completeness? (:-)) Compare: I never saw anything written in Ada, that could not be implemented in Assembler... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-23 7:30 ` Jeffrey Carter 2011-07-23 9:29 ` Maciej Sobczak 2011-07-23 10:07 ` Dmitry A. Kazakov @ 2011-07-26 21:04 ` Randy Brukardt 2011-07-26 23:43 ` Jeffrey Carter 2 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-07-26 21:04 UTC (permalink / raw) "Jeffrey Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message news:j0e0l1$5qh$1@tornado.tornevall.net... > On 07/22/2011 03:59 PM, Randy Brukardt wrote: >> >> Given that the problem in question is related to dynamic dispatching and >> has >> nothing in particular to do with extensions, this is an amazing >> statement. > > My statement was tongue in cheek, intended to express my dislike for > tagged types. Their only value seems to be all the traffic here from > people who run into problems trying to use them; this would be a much > quieter place without them. > > Maybe I'm missing something, but it seems to me that all dispatching in > Ada is related to extensions. If you have > > type T is tagged ... > > procedure P (V : in out T); > > and you never extend T, then you never get dispatching (in the sense that > a call to P results in something other than this P being called). To get > dispatching, you have to extend T > > type T2 is new T with ... > > overriding procedure P (V : in out T2); > > Then you can get a single call that sometimes calls P for T and other > times P for T2; that's dispatching. I don't know what dispatching means > without an extension and an overridden subprogram to dispatch to. You're right in language terms, but as Dmitry points out, this occurs only because we're discussing tagged types (which include 3 of the 4 OOP legs in a single package). I was thinking more generally (and yes, I just complained about Dmitry doing that); what I was thinking of by "extension" was actually adding components to a type, not just deriving a a type with the same set of components. As I was describing, most of the use of dispatching in Claw does not use any extension (that is, adding new components), it just changes the behavior of the dispatching routines appropriately. So there is only a change in behavior, not a change in representation. Others have pointed out that using case statements as you suggested is essentially worthless unless you know every entity that the program is going to process before the fact. And real world programs are not like that (I have plenty of experience changing hundreds of case statements each time we make a change in node types or intermediate code definitions in Janus/Ada). Randy. >> OTOH, programming by composition would provide nothing, in that there >> would >> be no way to change the handlers for the base type. One could graft some >> sort of unstructured mechanism on top of the objects (possibly using >> access-to-subprograms), but this would provide many more opportunities >> for >> mistakes (if you forget to set the access-to-subprogram value, the >> routine >> might as well not exist). > > The equivalent of dispatching in programming by composition is a > subprogram that contains a case statement that contains calls to other > subprograms. No access-to-subprogram values involved. It does the exact > same thing as dispatching, except that it's easier to read and understand > and doesn't result in large numbers of "what am I doing wrong?" posts to > c.l.a. > >> Remember that there are four legs to the OOP stool: strong typing, >> encapsulation, extension, and dynamic dispatching -- and each of these is >> orthogonal to the others (shown by the fact that Ada has the first two >> without even using tagged types, that is OOP). So there is no necessary >> relationship between extension and dispatching (and working around the >> one >> does nothing to solve a problem that mainly depends on the other). > > Again, I have no idea what dispatching even means in the absence of > extension. > > In Ada, "programming by extension" is achieved by the use of tagged types; > it includes dispatching. I have never seen anything implemented using > tagged types that could not also be implemented using programming by > composition. It follows that if there is a case where tagged types cause a > problem, the equivalent solution without tagged types is an effective work > around to the problem. > > Of course, in the case where there is no solution using tagged types, > there may also be no solution without using them. > > -- > Jeff Carter > "If you think you got a nasty taunting this time, > you ain't heard nothing yet!" > Monty Python and the Holy Grail > 23 ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-26 21:04 ` Randy Brukardt @ 2011-07-26 23:43 ` Jeffrey Carter 2011-07-27 23:56 ` Randy Brukardt 2011-07-28 10:06 ` Maciej Sobczak 0 siblings, 2 replies; 63+ messages in thread From: Jeffrey Carter @ 2011-07-26 23:43 UTC (permalink / raw) On 07/26/2011 02:04 PM, Randy Brukardt wrote: > > You're right in language terms, but as Dmitry points out, this occurs only > because we're discussing tagged types (which include 3 of the 4 OOP legs in a > single package). I was thinking more generally (and yes, I just complained > about Dmitry doing that); what I was thinking of by "extension" was actually > adding components to a type, not just deriving a a type with the same set of > components. > > As I was describing, most of the use of dispatching in Claw does not use any > extension (that is, adding new components), it just changes the behavior of > the dispatching routines appropriately. So there is only a change in > behavior, not a change in representation. ARM 3.9.1 defines a type extension as record_extension_part ::= with record_definition and record_definition includes "null record", so these are all extensions and examples of programming by extension. I wouldn't have thought that I'd have to define what I meant when using an Ada term with you. > Others have pointed out that using case statements as you suggested is > essentially worthless unless you know every entity that the program is going > to process before the fact. And real world programs are not like that (I have > plenty of experience changing hundreds of case statements each time we make a > change in node types or intermediate code definitions in Janus/Ada). Yes, it's called "design", and it's part of what distinguishes S/W engineers from coders. As you note, it's an iterative process. The extra work and extra code is worth it for the significant improvement in ease of reading and understanding that results. -- Jeff Carter "I was in love with a beautiful blonde once, dear. She drove me to drink. That's the one thing I'm indebted to her for." Never Give a Sucker an Even Break 109 ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-26 23:43 ` Jeffrey Carter @ 2011-07-27 23:56 ` Randy Brukardt 2011-07-28 0:18 ` Jeffrey Carter 2011-07-28 10:06 ` Maciej Sobczak 1 sibling, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-07-27 23:56 UTC (permalink / raw) "Jeffrey Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message news:j0nmqd$voi$1@tornado.tornevall.net... > On 07/26/2011 02:04 PM, Randy Brukardt wrote: ... > and record_definition includes "null record", so these are all extensions > and > examples of programming by extension. I wouldn't have thought that I'd > have to > define what I meant when using an Ada term with you. I wasn't thinking of it as an Ada term. My mistake. >> Others have pointed out that using case statements as you suggested is >> essentially worthless unless you know every entity that the program is >> going >> to process before the fact. And real world programs are not like that (I >> have >> plenty of experience changing hundreds of case statements each time we >> make a >> change in node types or intermediate code definitions in Janus/Ada). > > Yes, it's called "design", and it's part of what distinguishes S/W > engineers > from coders. As you note, it's an iterative process. The extra work and > extra > code is worth it for the significant improvement in ease of reading and > understanding that results. I don't agree; the 30 page case statements found in our optimizer and some other parts of our compiler don't add anything to ease of reading! And there is no choice with case statements, you have to have a bunch of lines for each option; when there are literally hundreds of options there is no way to simplify. And updating those cases typically takes about a week's work; it is so time consuming that we avoid making changes to the intermediate code if any workaround can be found even when that is the best solution to a problem. Ada 2012 will help a tiny bit by providing useful set subtypes (even if they aren't called that), so at least it will be possible to give a name to groups of discontiguous enumerations and that will reduce the work in some cases. I admit that dispatching takes a leap of faith ("it just works" when used properly), and not everyone seems to be able to understand it. But having a lot less code in the critical parts of the application should help understanding. Note that OOP (at least in Ada) does not really provide an answer for the "it takes a week to modify" problem. The Claw Builder (a full OOP design) has a similar problem in the other dimension, in that defining all of the needed overrides also takes a week or so. And in neither case (OOP or non-OOP) is is usefully possible to do just part of the work (as an agile programmer such as myself would prefer) -- neither program will even compile until all of the overridings or case statements are defined. Either way, Ada makes it too hard to add new abstractions to an existing set. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-27 23:56 ` Randy Brukardt @ 2011-07-28 0:18 ` Jeffrey Carter 0 siblings, 0 replies; 63+ messages in thread From: Jeffrey Carter @ 2011-07-28 0:18 UTC (permalink / raw) On 07/27/2011 04:56 PM, Randy Brukardt wrote: > > I don't agree; the 30 page case statements found in our optimizer and some > other parts of our compiler don't add anything to ease of reading! And there > is no choice with case statements, you have to have a bunch of lines for > each option; when there are literally hundreds of options there is no way to > simplify. > > And updating those cases typically takes about a week's work; it is so time > consuming that we avoid making changes to the intermediate code if any > workaround can be found even when that is the best solution to a problem. There are as many options and as many lines of code per option no matter which implementation technique you use. At least with composition they're all together in one place; programming by extension puts them in as many places as there are options, with no links in the code to tell you where they are; the odds of leaving some options unmodified is much greater. As you mentioned later, it doesn't save you any effort, either. > I admit that dispatching takes a leap of faith ("it just works" when used > properly), and not everyone seems to be able to understand it. But having a > lot less code in the critical parts of the application should help > understanding. Everyone I know who has worked with code that uses programming by extension misunderstands it at least some of the time. (Perhaps you are an exception.) Composition does not seem to have this problem. -- Jeff Carter "Propose to an Englishman any principle, or any instrument, however admirable, and you will observe that the whole effort of the English mind is directed to find a difficulty, a defect, or an impossibility in it. If you speak to him of a machine for peeling a potato, he will pronounce it impossible: if you peel a potato with it before his eyes, he will declare it useless, because it will not slice a pineapple." Charles Babbage 92 ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-26 23:43 ` Jeffrey Carter 2011-07-27 23:56 ` Randy Brukardt @ 2011-07-28 10:06 ` Maciej Sobczak 2011-07-28 23:24 ` Randy Brukardt 1 sibling, 1 reply; 63+ messages in thread From: Maciej Sobczak @ 2011-07-28 10:06 UTC (permalink / raw) On Jul 27, 1:43 am, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org> wrote: > > Others have pointed out that using case statements as you suggested is > > essentially worthless unless you know every entity that the program is going > > to process before the fact. And real world programs are not like that > Yes, it's called "design", and it's part of what distinguishes S/W engineers > from coders. This statement is unfair and uses a very superficial argumentation. No matter how much extensive is the "design" and how good are the S/W engineers doing it, a complete view on the system is not always feasible. Software is built from components that are prepared in separation, possibly by different vendors. They have no way to know the complete set of types that will be used in the final system, as the final system might not be even invented yet when the components are produced. Using the open/closed principle with the help of dispatching operations is the cleanest and the least intrusive way to integrate such components and generics are not always applicable - a canonical example is the web server component that delivers the client request to the layer that can handle it. I've yet to see an approach that is cleaner and less error-prone than the dispatching call via an interface type. > As you note, it's an iterative process. The extra work and extra > code is worth it It is iterative on which side? The extra work by whom? > for the significant improvement in ease of reading and > understanding that results. Did you try that with web servers? -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-28 10:06 ` Maciej Sobczak @ 2011-07-28 23:24 ` Randy Brukardt 2011-07-29 6:45 ` Simon Wright 2011-08-09 21:10 ` Maciej Sobczak 0 siblings, 2 replies; 63+ messages in thread From: Randy Brukardt @ 2011-07-28 23:24 UTC (permalink / raw) "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message news:b0633538-6038-4167-860f-65ee9e7cddcc@k9g2000yqf.googlegroups.com... On Jul 27, 1:43 am, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org> wrote: ... >> for the significant improvement in ease of reading and >> understanding that results. > >Did you try that with web servers? Fasinating. While I agree with most of your points, it is interesting that the web server that runs the AdaIC archive site, the ada-auth.org site, the search engine for the RM, and RR Software's web site (which is an all-Ada design based on Claw's socket library) uses very little OOP. The only OOP in it is in the low-level socket operations, mainly because Claw sockets are an OOP design. But all of the high-level stuff is implemented as a table-driven approach (special handling, domain roots, and the like are all described in data form), and the specialty handlers (like the search engine) are all called from case statements driven from those data tables. The design was driven by an extra-paranoid approach to security: if the server had any way for a URL to execute foreign code (a plug-in), then it is highly likely that an attacker would find a way to use buggy URL to execute some foreign code of their choice. Thus the ability to execute foreign code is not provided at all -- all handlers have to compiled into the web server. (Combined with Ada's near prevention of buffer overflows and stack attacks, the two most common vectors of the time were firmly plugged. Of course, traversal prevention and sanitization of parameters still have to be accomplished -- there is no silver bullet to security.) Once you've done that, there isn't much benefit to an OOP approach, since you have to enumerate all of the handlers somewhere in any case. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-28 23:24 ` Randy Brukardt @ 2011-07-29 6:45 ` Simon Wright 2011-07-30 0:04 ` Randy Brukardt 2011-08-09 21:10 ` Maciej Sobczak 1 sibling, 1 reply; 63+ messages in thread From: Simon Wright @ 2011-07-29 6:45 UTC (permalink / raw) "Randy Brukardt" <randy@rrsoftware.com> writes: > The design was driven by an extra-paranoid approach to security: if > the server had any way for a URL to execute foreign code (a plug-in), > then it is highly likely that an attacker would find a way to use > buggy URL to execute some foreign code of their choice. Thus the > ability to execute foreign code is not provided at all -- all handlers > have to compiled into the web server. (Combined with Ada's near > prevention of buffer overflows and stack attacks, the two most common > vectors of the time were firmly plugged. Of course, traversal > prevention and sanitization of parameters still have to be > accomplished -- there is no silver bullet to security.) Once you've > done that, there isn't much benefit to an OOP approach, since you have > to enumerate all of the handlers somewhere in any case. Interesting. I'd have thought that "implementing the server using OOP" and "not providing plugin facilities" were quite separate things. The OOP approach could, I suppose, be thought of as a way to provide you (Randy) with plugin facilities, but not attackers! ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-29 6:45 ` Simon Wright @ 2011-07-30 0:04 ` Randy Brukardt 2011-07-30 6:32 ` Simon Wright 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-07-30 0:04 UTC (permalink / raw) "Simon Wright" <simon@pushface.org> wrote in message news:m2sjpp4mar.fsf@pushface.org... > "Randy Brukardt" <randy@rrsoftware.com> writes: > >> The design was driven by an extra-paranoid approach to security: if >> the server had any way for a URL to execute foreign code (a plug-in), >> then it is highly likely that an attacker would find a way to use >> buggy URL to execute some foreign code of their choice. Thus the >> ability to execute foreign code is not provided at all -- all handlers >> have to compiled into the web server. (Combined with Ada's near >> prevention of buffer overflows and stack attacks, the two most common >> vectors of the time were firmly plugged. Of course, traversal >> prevention and sanitization of parameters still have to be >> accomplished -- there is no silver bullet to security.) Once you've >> done that, there isn't much benefit to an OOP approach, since you have >> to enumerate all of the handlers somewhere in any case. > > Interesting. I'd have thought that "implementing the server using OOP" > and "not providing plugin facilities" were quite separate things. The > OOP approach could, I suppose, be thought of as a way to provide you > (Randy) with plugin facilities, but not attackers! The root of the problem is that Ada 95 had no way to create a factory short of writing a giant case statement. That's annoying but OK if you have a complex interface with many operations to implement. However, the web server only has a single interface ("here's a URL and a socket, write the result to the socket"). So there is no advantage to having a separate case statement in the factory - that would just add complexity. (The output to the socket has many helper routines in order to make it easier to write the correct formats, but in any case the output is nearly free-form text and there is no obvious advantage to any extensions there.) Even in Ada 2005 (which has somewhat better support for factories), you still have to "with" all of the units involved. It isn't much harder to write calls into a case statement (especially given the simplity of the interface). The dynamic is different if the interface is more complex. For instance, the output modules of the ARM formatter program are based on an OOP-design (these output in various formats: RTF, HTML, plain text, etc.). For that, there is a case statement in the main program to select which output format is desired. But the interface has a significant number of routines to deal with output formatting, particularly of graphics and tables. Having to maintain 50 case statements would not be anywhere near as clean as the OOP design. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-30 0:04 ` Randy Brukardt @ 2011-07-30 6:32 ` Simon Wright 2011-08-01 9:30 ` Alex R. Mosteo 0 siblings, 1 reply; 63+ messages in thread From: Simon Wright @ 2011-07-30 6:32 UTC (permalink / raw) "Randy Brukardt" <randy@rrsoftware.com> writes: > "Simon Wright" <simon@pushface.org> wrote in message > news:m2sjpp4mar.fsf@pushface.org... >> "Randy Brukardt" <randy@rrsoftware.com> writes: >> >>> The design was driven by an extra-paranoid approach to security: if >>> the server had any way for a URL to execute foreign code (a >>> plug-in), then it is highly likely that an attacker would find a way >>> to use buggy URL to execute some foreign code of their choice. Thus >>> the ability to execute foreign code is not provided at all -- all >>> handlers have to compiled into the web server. (Combined with Ada's >>> near prevention of buffer overflows and stack attacks, the two most >>> common vectors of the time were firmly plugged. Of course, traversal >>> prevention and sanitization of parameters still have to be >>> accomplished -- there is no silver bullet to security.) Once you've >>> done that, there isn't much benefit to an OOP approach, since you >>> have to enumerate all of the handlers somewhere in any case. >> >> Interesting. I'd have thought that "implementing the server using >> OOP" and "not providing plugin facilities" were quite separate >> things. The OOP approach could, I suppose, be thought of as a way to >> provide you (Randy) with plugin facilities, but not attackers! > > The root of the problem is that Ada 95 had no way to create a factory > short of writing a giant case statement. That's annoying but OK if you > have a complex interface with many operations to implement. However, > the web server only has a single interface ("here's a URL and a > socket, write the result to the socket"). So there is no advantage to > having a separate case statement in the factory - that would just add > complexity. (The output to the socket has many helper routines in > order to make it easier to write the correct formats, but in any case > the output is nearly free-form text and there is no obvious advantage > to any extensions there.) > > Even in Ada 2005 (which has somewhat better support for factories), > you still have to "with" all of the units involved. It isn't much > harder to write calls into a case statement (especially given the > simplity of the interface). In my EWS (https://sourceforge.net/projects/embed-web-srvr/) there are two 'classes' of response, Static and Dynamic. For static responses, the page to be returned is fixed, and is baked in at build time. For dynamic responses, I have a function type Creator is access function (From_Request : HTTP.Request_P) return Dynamic_Response'Class; and a means of registering Creators procedure Register (The_Creator : Creator; For_The_URL : HTTP.URL); ('URL' isn't quite right, it's the 'abs_path [ "?" query ]' part of an HTTP URL, eg /embed-web-srvr/ in the URL above). For_The_URL is really a String, and the result of registration is effectively a run-time factory. But no case statements! ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-30 6:32 ` Simon Wright @ 2011-08-01 9:30 ` Alex R. Mosteo 2011-08-01 10:12 ` Dmitry A. Kazakov 0 siblings, 1 reply; 63+ messages in thread From: Alex R. Mosteo @ 2011-08-01 9:30 UTC (permalink / raw) Simon Wright wrote: > "Randy Brukardt" <randy@rrsoftware.com> writes: > >> "Simon Wright" <simon@pushface.org> wrote in message >> news:m2sjpp4mar.fsf@pushface.org... >>> "Randy Brukardt" <randy@rrsoftware.com> writes: >>> >>>> The design was driven by an extra-paranoid approach to security: if >>>> the server had any way for a URL to execute foreign code (a >>>> plug-in), then it is highly likely that an attacker would find a way >>>> to use buggy URL to execute some foreign code of their choice. Thus >>>> the ability to execute foreign code is not provided at all -- all >>>> handlers have to compiled into the web server. (Combined with Ada's >>>> near prevention of buffer overflows and stack attacks, the two most >>>> common vectors of the time were firmly plugged. Of course, traversal >>>> prevention and sanitization of parameters still have to be >>>> accomplished -- there is no silver bullet to security.) Once you've >>>> done that, there isn't much benefit to an OOP approach, since you >>>> have to enumerate all of the handlers somewhere in any case. >>> >>> Interesting. I'd have thought that "implementing the server using >>> OOP" and "not providing plugin facilities" were quite separate >>> things. The OOP approach could, I suppose, be thought of as a way to >>> provide you (Randy) with plugin facilities, but not attackers! >> >> The root of the problem is that Ada 95 had no way to create a factory >> short of writing a giant case statement. That's annoying but OK if you >> have a complex interface with many operations to implement. However, >> the web server only has a single interface ("here's a URL and a >> socket, write the result to the socket"). So there is no advantage to >> having a separate case statement in the factory - that would just add >> complexity. (The output to the socket has many helper routines in >> order to make it easier to write the correct formats, but in any case >> the output is nearly free-form text and there is no obvious advantage >> to any extensions there.) >> >> Even in Ada 2005 (which has somewhat better support for factories), >> you still have to "with" all of the units involved. It isn't much >> harder to write calls into a case statement (especially given the >> simplity of the interface). > > In my EWS (https://sourceforge.net/projects/embed-web-srvr/) there are > two 'classes' of response, Static and Dynamic. For static responses, the > page to be returned is fixed, and is baked in at build time. For dynamic > responses, I have a function > > type Creator > is access function (From_Request : HTTP.Request_P) > return Dynamic_Response'Class; > > and a means of registering Creators > > procedure Register (The_Creator : Creator; For_The_URL : HTTP.URL); > > ('URL' isn't quite right, it's the 'abs_path [ "?" query ]' part of an > HTTP URL, eg /embed-web-srvr/ in the URL above). > > For_The_URL is really a String, and the result of registration is > effectively a run-time factory. But no case statements! I have done basically the same for my component-based robotic library, but still you have to /with/ all the units you want and call the register procedure... Still, I find this sufficiently neat (you don't have to edit any central piece of code (besides the main procedure, but that's OK to me --you're expressing your necessities there). ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-01 9:30 ` Alex R. Mosteo @ 2011-08-01 10:12 ` Dmitry A. Kazakov 2011-08-01 21:56 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-01 10:12 UTC (permalink / raw) On Mon, 01 Aug 2011 11:30:33 +0200, Alex R. Mosteo wrote: > Simon Wright wrote: > >> "Randy Brukardt" <randy@rrsoftware.com> writes: >> >>> "Simon Wright" <simon@pushface.org> wrote in message >>> news:m2sjpp4mar.fsf@pushface.org... >>>> "Randy Brukardt" <randy@rrsoftware.com> writes: >>>> >>>>> The design was driven by an extra-paranoid approach to security: if >>>>> the server had any way for a URL to execute foreign code (a >>>>> plug-in), then it is highly likely that an attacker would find a way >>>>> to use buggy URL to execute some foreign code of their choice. Thus >>>>> the ability to execute foreign code is not provided at all -- all >>>>> handlers have to compiled into the web server. (Combined with Ada's >>>>> near prevention of buffer overflows and stack attacks, the two most >>>>> common vectors of the time were firmly plugged. Of course, traversal >>>>> prevention and sanitization of parameters still have to be >>>>> accomplished -- there is no silver bullet to security.) Once you've >>>>> done that, there isn't much benefit to an OOP approach, since you >>>>> have to enumerate all of the handlers somewhere in any case. >>>> >>>> Interesting. I'd have thought that "implementing the server using >>>> OOP" and "not providing plugin facilities" were quite separate >>>> things. The OOP approach could, I suppose, be thought of as a way to >>>> provide you (Randy) with plugin facilities, but not attackers! >>> >>> The root of the problem is that Ada 95 had no way to create a factory >>> short of writing a giant case statement. That's annoying but OK if you >>> have a complex interface with many operations to implement. However, >>> the web server only has a single interface ("here's a URL and a >>> socket, write the result to the socket"). So there is no advantage to >>> having a separate case statement in the factory - that would just add >>> complexity. (The output to the socket has many helper routines in >>> order to make it easier to write the correct formats, but in any case >>> the output is nearly free-form text and there is no obvious advantage >>> to any extensions there.) >>> >>> Even in Ada 2005 (which has somewhat better support for factories), >>> you still have to "with" all of the units involved. It isn't much >>> harder to write calls into a case statement (especially given the >>> simplity of the interface). >> >> In my EWS (https://sourceforge.net/projects/embed-web-srvr/) there are >> two 'classes' of response, Static and Dynamic. For static responses, the >> page to be returned is fixed, and is baked in at build time. For dynamic >> responses, I have a function >> >> type Creator >> is access function (From_Request : HTTP.Request_P) >> return Dynamic_Response'Class; >> >> and a means of registering Creators >> >> procedure Register (The_Creator : Creator; For_The_URL : HTTP.URL); >> >> ('URL' isn't quite right, it's the 'abs_path [ "?" query ]' part of an >> HTTP URL, eg /embed-web-srvr/ in the URL above). >> >> For_The_URL is really a String, and the result of registration is >> effectively a run-time factory. But no case statements! > > I have done basically the same for my component-based robotic library, but > still you have to /with/ all the units you want and call the register > procedure... You have not. The procedure Register is called from the body of the package that provides an implementation. It adds an entry into the global map id -> object constructor. The object factory sees only this map, it need not to with any implementations. This is the way I implement persistency layers. BTW, Generic_Dispatching_Constructor of Ada 2005 did not change much to Ada 95 because of tags. You still need a registering layer to maintain external name to tag mapping. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-01 10:12 ` Dmitry A. Kazakov @ 2011-08-01 21:56 ` Randy Brukardt 2011-08-02 10:03 ` Dmitry A. Kazakov 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-01 21:56 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1rlxo1uthv5xt.1agapd9q0mek4$.dlg@40tude.net... ... > BTW, Generic_Dispatching_Constructor of Ada 2005 did not change much to > Ada > 95 because of tags. You still need a registering layer to maintain > external > name to tag mapping. It did eliminate one thing, the need to have a scheme to create an object of each tagged type. That forced the use of either a case statement or an access-to-subprogram, either of which is error-prone. There is no possibility of eliminating the need for some sort of registry -- although in some cases you can use the one built-into the language (the External_Tag). There has to be a mapping somewhere of some sort of key to a tag, since it isn't possible to export tags to the "real world". Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-01 21:56 ` Randy Brukardt @ 2011-08-02 10:03 ` Dmitry A. Kazakov 2011-08-02 21:16 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-02 10:03 UTC (permalink / raw) On Mon, 1 Aug 2011 16:56:17 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1rlxo1uthv5xt.1agapd9q0mek4$.dlg@40tude.net... > ... >> BTW, Generic_Dispatching_Constructor of Ada 2005 did not change much to >> Ada >> 95 because of tags. You still need a registering layer to maintain >> external name to tag mapping. > > It did eliminate one thing, the need to have a scheme to create an object of > each tagged type. That forced the use of either a case statement or an > access-to-subprogram, either of which is error-prone. I don't consider the case statement because it is just a wrong pattern. Regarding mappings type ID to either a constructing function or tag, they are equivalent. Both require the same amount of maintenance. > There is no possibility of eliminating the need for some sort of registry -- > although in some cases you can use the one built-into the language (the > External_Tag). There has to be a mapping somewhere of some sort of key to a > tag, since it isn't possible to export tags to the "real world". It is possible, and even required for distributed weakly coupled applications, but in order to do that you have to export the types themselves rather than their tags. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-02 10:03 ` Dmitry A. Kazakov @ 2011-08-02 21:16 ` Randy Brukardt 2011-08-03 9:01 ` Dmitry A. Kazakov 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-02 21:16 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1nvqqny2226ro$.1ixvoiht8zu8l$.dlg@40tude.net... > On Mon, 1 Aug 2011 16:56:17 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1rlxo1uthv5xt.1agapd9q0mek4$.dlg@40tude.net... >> ... >>> BTW, Generic_Dispatching_Constructor of Ada 2005 did not change much to >>> Ada >>> 95 because of tags. You still need a registering layer to maintain >>> external name to tag mapping. >> >> It did eliminate one thing, the need to have a scheme to create an object >> of >> each tagged type. That forced the use of either a case statement or an >> access-to-subprogram, either of which is error-prone. > > I don't consider the case statement because it is just a wrong pattern. > Regarding mappings type ID to either a constructing function or tag, they > are equivalent. Both require the same amount of maintenance. There are more sources of error when using access-to-subprogram; it's easy to forget to create a routine or use the wrong one. Neither of those are possible with generic dispatching constructor (or with a case statement, for that matter, presuming that you use Ada's completeness checks). This is a minor advantage, but it is real; it's the major reason that I don't even think about using access-to-subprogram (and have to be reminded of the possibility). >> There is no possibility of eliminating the need for some sort of registry -- >> although in some cases you can use the one built-into the language (the >> External_Tag). There has to be a mapping somewhere of some sort of key to >> a >> tag, since it isn't possible to export tags to the "real world". > > It is possible, and even required for distributed weakly coupled > applications, but in order to do that you have to export the types > themselves rather than their tags. It might be possible for some non-Ada language, but it's not possible for Ada (and this is an Ada site and I was only talking about Ada here). There is no way in Ada to "export the types"; you have to export some type indication -- and that requires some sort of mapping of indication to type. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-02 21:16 ` Randy Brukardt @ 2011-08-03 9:01 ` Dmitry A. Kazakov 2011-08-03 20:16 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-03 9:01 UTC (permalink / raw) On Tue, 2 Aug 2011 16:16:27 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1nvqqny2226ro$.1ixvoiht8zu8l$.dlg@40tude.net... >> On Mon, 1 Aug 2011 16:56:17 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:1rlxo1uthv5xt.1agapd9q0mek4$.dlg@40tude.net... >>> ... >>>> BTW, Generic_Dispatching_Constructor of Ada 2005 did not change much to >>>> Ada >>>> 95 because of tags. You still need a registering layer to maintain >>>> external name to tag mapping. >>> >>> It did eliminate one thing, the need to have a scheme to create an object >>> of >>> each tagged type. That forced the use of either a case statement or an >>> access-to-subprogram, either of which is error-prone. >> >> I don't consider the case statement because it is just a wrong pattern. >> Regarding mappings type ID to either a constructing function or tag, they >> are equivalent. Both require the same amount of maintenance. > > There are more sources of error when using access-to-subprogram; it's easy > to forget to create a routine or use the wrong one. Yes there is some advantage that the function in dispatching constructor is primitive: function Create (...) return T; For access-to-subprogram it is class-wide: function Create (...) return T'Class; As for using a wrong subprogram you can also register a wrong tag. That is same. BTW, the patterns are: -- with generic dispatching constructor type T is tagged ...; function Create (...) return T; procedure Register (ID : ID_Type; Construct : Tag); --- Usage: package P is type S is new T with ...; overriding function Create (...) return S; end P; package body P is ... begin Register (S_ID, S'Tag); end P; vs. -- Ada 95 access-to-subprogram solution type T is tagged ...; type Factory is access function Create (...) return T'Class; procedure Register (ID : ID_Type; Constructor : Factory); -- Usage: package P is type S is new T with ...; end P; package body P is function Create (...) return T'Class is ... end Create; ... begin Register (S_ID, Create'Access); end P; >>> There is no possibility of eliminating the need for some sort of registry -- >>> although in some cases you can use the one built-into the language (the >>> External_Tag). There has to be a mapping somewhere of some sort of key to a >>> tag, since it isn't possible to export tags to the "real world". >> >> It is possible, and even required for distributed weakly coupled >> applications, but in order to do that you have to export the types >> themselves rather than their tags. > > It might be possible for some non-Ada language, but it's not possible for > Ada (and this is an Ada site and I was only talking about Ada here). Well, if Ada designers are serious about addressing distributed systems (Annex E), that has to happen. Either a kind of IDL must be put into the Ada standard (highly undesired) or some other, more reasonable, means must be provided to populate types. [Of course the type system must be brought in order before even considering this sort of issues.] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-03 9:01 ` Dmitry A. Kazakov @ 2011-08-03 20:16 ` Randy Brukardt 2011-08-04 8:15 ` Dmitry A. Kazakov 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-03 20:16 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:nwyetwf3hqn7$.gm3c388p0s3c$.dlg@40tude.net... > On Tue, 2 Aug 2011 16:16:27 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1nvqqny2226ro$.1ixvoiht8zu8l$.dlg@40tude.net... >>> On Mon, 1 Aug 2011 16:56:17 -0500, Randy Brukardt wrote: ... >>>> It did eliminate one thing, the need to have a scheme to create an >>>> object of >>>> each tagged type. That forced the use of either a case statement or an >>>> access-to-subprogram, either of which is error-prone. >>> >>> I don't consider the case statement because it is just a wrong pattern. >>> Regarding mappings type ID to either a constructing function or tag, >>> they >>> are equivalent. Both require the same amount of maintenance. >> >> There are more sources of error when using access-to-subprogram; it's >> easy >> to forget to create a routine or use the wrong one. > > Yes there is some advantage that the function in dispatching constructor > is > primitive: > > function Create (...) return T; There's another advantage (for this use): the language requires you to override it, or you get an error. So it is impossible to forget to write the routine or have it return the wrong kind of object. Errors of omission are the hardest to find, and this property at least prevents those errors. (Of course, it doesn't prevent putting the wrong contents into that object.) Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-03 20:16 ` Randy Brukardt @ 2011-08-04 8:15 ` Dmitry A. Kazakov 0 siblings, 0 replies; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-04 8:15 UTC (permalink / raw) On Wed, 3 Aug 2011 15:16:08 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:nwyetwf3hqn7$.gm3c388p0s3c$.dlg@40tude.net... >> Yes there is some advantage that the function in dispatching constructor is >> primitive: >> >> function Create (...) return T; > > There's another advantage (for this use): the language requires you to > override it, or you get an error. Yes, this is the advantage I had in mind. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-28 23:24 ` Randy Brukardt 2011-07-29 6:45 ` Simon Wright @ 2011-08-09 21:10 ` Maciej Sobczak 2011-08-09 21:35 ` Randy Brukardt 1 sibling, 1 reply; 63+ messages in thread From: Maciej Sobczak @ 2011-08-09 21:10 UTC (permalink / raw) On Jul 29, 1:24 am, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > >Did you try that with web servers? > > Fasinating. While I agree with most of your points, it is interesting that > the web server that runs the AdaIC archive site, [...] > the specialty handlers (like the search engine) are all > called from case statements driven from those data tables. I assume that this particular web server was written from scratch and on top of some lower-level primitives (sockets). That's OK, but very likely an overkill. That's why I have mentioned the possibility to integrate off-the-shelf components, in which case there is simply no place to put your case statement. > The design was driven by an extra-paranoid approach to security: if the > server had any way for a URL to execute foreign code (a plug-in), I don't see any conflict between OOP and security here. The complete application can be statically bound, in which case the execution of dynamically loaded code is excluded. What I'm talking about is a kind of dependency inversion - instead of the web server calling each particular module from some single giant case statement (which has to with all packages, etc.), you might have a set of modules that register themselves in a single registry, which is later used to resolve the call. By doing this, the web server and its registry do not have to with anything other than the common interface specification. Of course, you might still need to do some magic in order to force all those modules to elaborate/initialize (so that they can register in the web server central module), which might turn out to be a ladder of with clauses that we wanted to avoid in the first place, but this has nothing to do with OOP - it is only a peculiarity of Ada and I can imagine a language where this can be done externally by a build script or even by a mere presence of source files. We can also think about the automated generation of the with statements that are need to force the elaboration of all modules. But then - the giant case statement can be also automatically generated, which could in turn be taken as an argument against OOP. Oh, dear... :-) Still, I believe that the open/close principle and the dependency inversion are two (only?) good use cases for dispatching and that when this design approach is needed, the dispatching offers the cleanest solution. -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-09 21:10 ` Maciej Sobczak @ 2011-08-09 21:35 ` Randy Brukardt 2011-08-10 9:11 ` Dmitry A. Kazakov 2011-08-10 10:07 ` Maciej Sobczak 0 siblings, 2 replies; 63+ messages in thread From: Randy Brukardt @ 2011-08-09 21:35 UTC (permalink / raw) "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message news:4a4f185d-5268-4d73-a5df-8149bd117e0f@h9g2000vbr.googlegroups.com... On Jul 29, 1:24 am, "Randy Brukardt" <ra...@rrsoftware.com> wrote: >> >Did you try that with web servers? >> >> Fasinating. While I agree with most of your points, it is interesting >> that >> the web server that runs the AdaIC archive site, [...] >> the specialty handlers (like the search engine) are all >> called from case statements driven from those data tables. >I assume that this particular web server was written from scratch and >on top of some lower-level primitives (sockets). The Claw sockets and HTTP packages, to be specific. > That's OK, but very > likely an overkill. That's why I have mentioned the possibility to > integrate off-the-shelf components, in which case there is simply no > place to put your case statement. What off-the-shelf components? We're talking about Ada here, and the only components I know of are procedural libraries. After all, the only part of the core web server not covered by the Claw components was the URL parser (completely procedural, basic string to string transformations), and the code to stream in files (predefined Ada components). The interesting parts are in the specialized handlers, and those were also built out of existing components (various proto-containers originated by Tom Moran, the crawler skelton that Tom created early on as a Claw sockets sample program, etc.) And none of those components use much OOP (or could). >> The design was driven by an extra-paranoid approach to security: if the >> server had any way for a URL to execute foreign code (a plug-in), > >I don't see any conflict between OOP and security here. The complete >application can be statically bound, in which case the execution of >dynamically loaded code is excluded. It's less of a conflict than a need; once the application is statically bound, most of the value of OOP vanishes (particularly when the requirements aren't likely to change much, as in this case). >What I'm talking about is a kind of dependency inversion - instead of >the web server calling each particular module from some single giant >case statement (which has to with all packages, etc.), you might have >a set of modules that register themselves in a single registry, which >is later used to resolve the call. By doing this, the web server and >its registry do not have to with anything other than the common >interface specification. Of course, you might still need to do some >magic in order to force all those modules to elaborate/initialize (so >that they can register in the web server central module), which might >turn out to be a ladder of with clauses that we wanted to avoid in the >first place, but this has nothing to do with OOP - it is only a >peculiarity of Ada and I can imagine a language where this can be done >externally by a build script or even by a mere presence of source >files. I mentioned all of that in one of my previous messages. The point is that in Ada, OOP doesn't help unless you have multiple interfaces associated with an object. That's not unusual, but it isn't always the case (and it isn't the case in the web server). >We can also think about the automated generation of the with >statements that are need to force the elaboration of all modules. >But then - the giant case statement can be also automatically >generated, which could in turn be taken as an argument against OOP. >Oh, dear... :-) Now you get it: the two organizations are equivalent in Ada if there is only a single interface. In which case, the simpler organization is probably better, especially if the lead designer was programming long before OOP was mainstream. :-) >Still, I believe that the open/close principle and the dependency >inversion are two (only?) good use cases for dispatching and that when >this design approach is needed, the dispatching offers the cleanest >solution. I don't see any dependency inversion in the web server. (The web server calls packages to evaluate particular commands or operations -- that's how almost all programs work!) This sounds more like a case of trying to make everything look like a nail (to the OOP hammer). I understand the value of the Open/Close principle, but it only is a win in Ada if there are multiple interfaces associated with an object. Otherwise, the amount of change is the same (or even less) for the non-OOP solution. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-09 21:35 ` Randy Brukardt @ 2011-08-10 9:11 ` Dmitry A. Kazakov 2011-08-10 21:56 ` Randy Brukardt 2011-08-10 10:07 ` Maciej Sobczak 1 sibling, 1 reply; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-10 9:11 UTC (permalink / raw) On Tue, 9 Aug 2011 16:35:14 -0500, Randy Brukardt wrote: > I understand the value of the Open/Close principle, but it only is a win in > Ada if there are multiple interfaces associated with an object. Otherwise, > the amount of change is the same (or even less) for the non-OOP solution. It could be true only if there were only one place of dispatch. In reality there are many dispatching calls and many class-wide operations (for which there is no typed procedural equivalent). Procedural solution would necessary have to bend design in order to reduce the number of such places, each requiring maintenance. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-10 9:11 ` Dmitry A. Kazakov @ 2011-08-10 21:56 ` Randy Brukardt 2011-08-11 8:07 ` Dmitry A. Kazakov 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-10 21:56 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1bs0xoar40rx.6yb23bgkfrew.dlg@40tude.net... > On Tue, 9 Aug 2011 16:35:14 -0500, Randy Brukardt wrote: > >> I understand the value of the Open/Close principle, but it only is a win >> in >> Ada if there are multiple interfaces associated with an object. >> Otherwise, >> the amount of change is the same (or even less) for the non-OOP solution. > > It could be true only if there were only one place of dispatch. That's exactly the case I meant. > In reality > there are many dispatching calls and many class-wide operations (for which > there is no typed procedural equivalent). Reality? The reality is in the web server interface I was describing there was only one such point of dispatch, and only a single interface to dispatch to. It's clearly a special case, but one that is pretty common in the systems I've worked on. All I was saying is that in that special case, there is no value to OOP in Ada. > Procedural solution would > necessary have to bend design in order to reduce the number of such > places, > each requiring maintenance. Not necessarily; a lot of problems have obvious bottlenecks where everything goes through a single point. Making complex dispatching designs in such cases only increases complexity and difficulty of maintenance. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-10 21:56 ` Randy Brukardt @ 2011-08-11 8:07 ` Dmitry A. Kazakov 2011-08-12 4:52 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-11 8:07 UTC (permalink / raw) On Wed, 10 Aug 2011 16:56:00 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1bs0xoar40rx.6yb23bgkfrew.dlg@40tude.net... >> In reality >> there are many dispatching calls and many class-wide operations (for which >> there is no typed procedural equivalent). > > Reality? The reality is in the web server interface I was describing there > was only one such point of dispatch, and only a single interface to dispatch > to. It's clearly a special case, but one that is pretty common in the > systems I've worked on. The problem is that starting a project without OO, you have to gamble on whether this indeed is a special case and will remain special. This is called fragile design. It is bad that Ada offers a choice between types having classes and types without classes. A decision which should not be taken at all. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-11 8:07 ` Dmitry A. Kazakov @ 2011-08-12 4:52 ` Randy Brukardt 2011-08-12 8:54 ` Dmitry A. Kazakov 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-12 4:52 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1luxw3i4h9z8e$.7a8ee3cf99u2.dlg@40tude.net... > On Wed, 10 Aug 2011 16:56:00 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1bs0xoar40rx.6yb23bgkfrew.dlg@40tude.net... > >>> In reality >>> there are many dispatching calls and many class-wide operations (for >>> which >>> there is no typed procedural equivalent). >> >> Reality? The reality is in the web server interface I was describing >> there >> was only one such point of dispatch, and only a single interface to >> dispatch >> to. It's clearly a special case, but one that is pretty common in the >> systems I've worked on. > > The problem is that starting a project without OO, you have to gamble on > whether this indeed is a special case and will remain special. > > This is called fragile design. No, this is called "agile development"! There is no circumstance where a designer can possibly predict all possible ways their project is going to evolve. It's silly to try. It doesn't matter how you design your interfaces -- you're going to have to change them at some point. And I've never seen any difference in the amount of work in a OOP design. If anything, the OOP designs are harder to modify -- adding a new interface to the ARM formatter or the Claw Builder takes a long time and requires inserting a lot of similar code in a number of packages. I've rarely seen that sort of behavior with a purely procedural design (probably because ad-hoc sharing of code is much easier in a procedural design). I could imagine that there could exist some extremely fancy tools for creating the common structures of all of those "implementations" of the new interfaces automatically -- but I'm not aware of any such thing for Ada -- and in any case, I wouldn't have one (I only use Janus/Ada tools for [virtually all] programming here; have to do so in order to figure out what needs to be improved). Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-12 4:52 ` Randy Brukardt @ 2011-08-12 8:54 ` Dmitry A. Kazakov 0 siblings, 0 replies; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-08-12 8:54 UTC (permalink / raw) On Thu, 11 Aug 2011 23:52:13 -0500, Randy Brukardt wrote: > It doesn't matter how you design your interfaces -- you're going to have to > change them at some point. Yes. But it does not imply that there should be no interfaces designed. > And I've never seen any difference in the amount > of work in a OOP design. I disagree, but in order to show the truth we would need some metrics and data. IMO, OO is just an evolution of the concept of ADT used to accommodate mathematical ideas of categories. Arguing against OO is arguing against types in general. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-09 21:35 ` Randy Brukardt 2011-08-10 9:11 ` Dmitry A. Kazakov @ 2011-08-10 10:07 ` Maciej Sobczak 2011-08-10 11:26 ` Georg Bauhaus 2011-08-10 22:21 ` Randy Brukardt 1 sibling, 2 replies; 63+ messages in thread From: Maciej Sobczak @ 2011-08-10 10:07 UTC (permalink / raw) On Aug 9, 11:35 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > I don't see any dependency inversion in the web server. (The web server > calls packages to evaluate particular commands or operations -- that's how > almost all programs work!) The dependency inversion is in the fact that the web server does not have to know the modules it is calling. It is enough if the modules know the web server (and its registry, to be exact) - thanks to this new modules can be added without touching the web server itself (that's the open/close principle at work now). What is needed for the dependency inversion to work is a spec of something common - in the case of OOP this is an interface. > This sounds more like a case of trying to make > everything look like a nail (to the OOP hammer). No, this is trying to reduce the effort to maintain a heavy component that is tested and verified only once. -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-10 10:07 ` Maciej Sobczak @ 2011-08-10 11:26 ` Georg Bauhaus 2011-08-10 22:27 ` Randy Brukardt 2011-08-10 22:21 ` Randy Brukardt 1 sibling, 1 reply; 63+ messages in thread From: Georg Bauhaus @ 2011-08-10 11:26 UTC (permalink / raw) On 10.08.11 12:07, Maciej Sobczak wrote: > On Aug 9, 11:35 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > >> I don't see any dependency inversion in the web server. (The web server >> calls packages to evaluate particular commands or operations -- that's how >> almost all programs work!) > > The dependency inversion is in the fact that the web server does not > have to know the modules it is calling. It is enough if the modules > know the web server (and its registry, to be exact) - thanks to this > new modules can be added without touching the web server itself > (that's the open/close principle at work now). What is needed for the > dependency inversion to work is a spec of something common - in the > case of OOP this is an interface. One example of this style of OOP web server at work is Google's mainframe operating system called App Engine. Programming for this web server, you will typically define request handler types and override one or more of the get/post/delete/... operations of a parent type. Next, you indicate which of your types should handle requests for which URL. The server software loads your programs, inspects them for request handler types, and runs the overridden subprograms (get/post/delete/...) when corresponding HTTP requests (GET/POST/DELETE/...) come in. (Requests will be from the web, or from the mainframe when it has been instructed run task queues, cron jobs, or pipelines.) I don't think Google will, or even could, change a rather large case statement whenever some new request handler is added to the system. The system is running large number of app engine programs, each having a number of request handler types. They use a registry. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-10 11:26 ` Georg Bauhaus @ 2011-08-10 22:27 ` Randy Brukardt 0 siblings, 0 replies; 63+ messages in thread From: Randy Brukardt @ 2011-08-10 22:27 UTC (permalink / raw) "Georg Bauhaus" <rm.dash-bauhaus@futureapps.de> wrote in message news:4e426ae0$0$6584$9b4e6d93@newsspool3.arcor-online.net... ... > I don't think Google will, or even could, change a rather > large case statement whenever some new request handler is > added to the system. The system is running large number of > app engine programs, each having a number of request handler > types. They use a registry. That's not remotely the same problem (see my other message - and indeed my original messages). If you have an open system, and don't care about security and correctness, then of course a registration scheme is far preferable. I'm paranoid enough that I'm not willing to allow anyone else to put code into the server without the extensive vetting of an Ada compiler. (This is one of the same reasons that I rarely make any of my code open source -- I don't trust anyone else near my code. Even with RRS, I always verify every change someone else makes before adding it to my personal copy -- I've saved a lot of wasted debugging time by doing that.) Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-10 10:07 ` Maciej Sobczak 2011-08-10 11:26 ` Georg Bauhaus @ 2011-08-10 22:21 ` Randy Brukardt 2011-08-11 13:50 ` Maciej Sobczak 1 sibling, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-10 22:21 UTC (permalink / raw) "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message news:b6049447-8479-46ca-82e8-b6031a4b4d1a@q15g2000yqk.googlegroups.com... On Aug 9, 11:35 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote: >> I don't see any dependency inversion in the web server. (The web server >> calls packages to evaluate particular commands or operations -- that's >> how >> almost all programs work!) > >The dependency inversion is in the fact that the web server does not >have to know the modules it is calling. It is enough if the modules >know the web server (and its registry, to be exact) - thanks to this >new modules can be added without touching the web server itself >(that's the open/close principle at work now). What is needed for the >dependency inversion to work is a spec of something common - in the >case of OOP this is an interface. But adding new modules without somehow modifying the web server is simply not allowed in the problem statement that I had (that is, all code that the server can execute is statically compiled into the web server). So there can be no "inversion" here -- some piece of the server needs to know about all of the code that it possibly can execute. (Ada requires with clauses at a minimum.) >> This sounds more like a case of trying to make >> everything look like a nail (to the OOP hammer). > >No, this is trying to reduce the effort to maintain a heavy component >that is tested and verified only once. I have no idea what you are talking about; no part of my web server (other than the case statement) is modified to add a new capability. [Note that something list the case statement has to exist in the OOP model anyway - ,at a minimum for with clauses and a series of registration calls (there is insufficient control over elaboration in Ada to use elaboration for that purpose in a real system).] I can explain the mechanism in a bit more detail. The web server has a data list of (normalized) URLs that require special handling, along with a special handling key. When the web server sees any of these, it calls the special handling interface routine (passing the record containing the GET parameters and the output socket). Otherwise, it tries to serve a normal web page. The special handling interface contains a case statement on the special handling keys, and calls the appropriate handler for each one. Since the original requirement was for all of the code to be statically compiled, that code is also part of the web server executable, and of course the special handling interface needs to be modified to add a new module. But it (and the data table) are the only things that need modification in this scenario. An OOP design would have been identical (the data table was intended to be modified "on the fly", although we never needed that capability and thus never implemented it - the data is just an Ada aggregate currently), with the exception that the case statement would be replaced by a registration routine that gathered all of the units together. I fail to see how that would have improved anything about the design. It would, however, have provided an easier way to make the design far more complex (and less maintainable, IMHO), by adding interfaces to support dubious capabilities (and thus changing the behavior of the core web server), rather than funneling everything through the interface. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-10 22:21 ` Randy Brukardt @ 2011-08-11 13:50 ` Maciej Sobczak 2011-08-12 4:43 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Maciej Sobczak @ 2011-08-11 13:50 UTC (permalink / raw) On Aug 11, 12:21 am, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > But adding new modules without somehow modifying the web server is simply > not allowed in the problem statement that I had (that is, all code that the > server can execute is statically compiled into the web server). I see - but isn't it a special case? The advantage of OOP is in its run-time nature. That is, the registry can be modified at run-time according to anything from startup options to real-time data input. Modifying a giant case statement (or is it a chain of ifs? after all, URLs are not discrete in the Ada sense) might be acceptable between deployment cycles of the given system, but making this structure dependent on some run-time values would be too much. Of course, I don't claim that such run-time liberty is always required, but is certainly more general. This is an important point when designing reusable components. That is, if you implement the final web server you might be in a position to define your problem completely (or not - see the "fragile design" risk that Dmitry mentioned), but if you implement the web server component for reuse in potentially many future systems, then targeting the more general problem seems to be a way to go. This is why message delivery in YAMI4 is based on callbacks via interfaces and why the object registration is dynamic - new objects (they correspond to message targets or inboxes) can be added and removed on the fly. This still allows a completely static structure where all components are known statically and wired at program startup, so in this sense both approaches are addressed without unnecessary compromises. I think that web servers are not much different from this - in fact, they do exactly the same stuff, which is delivering external stimuli to some program handler. I would certainly use OOP for this part of any reusable web server component. -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-11 13:50 ` Maciej Sobczak @ 2011-08-12 4:43 ` Randy Brukardt 2011-08-12 7:00 ` Maciej Sobczak 0 siblings, 1 reply; 63+ messages in thread From: Randy Brukardt @ 2011-08-12 4:43 UTC (permalink / raw) "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message news:f44209e4-8677-4995-8b17-d641bae2b698@hl8g2000vbb.googlegroups.com... >On Aug 11, 12:21 am, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > >> But adding new modules without somehow modifying the web server is simply >> not allowed in the problem statement that I had (that is, all code that >> the >> server can execute is statically compiled into the web server). > >I see - but isn't it a special case? Yes, in today's world, safety and security are surely a special case -- hardly anyone seems to care, and thus they get PWNed all the time. Yes, of course there are ways to enforce safety and security in a dynamic loading environment, but they aren't practical for a no-budget project (certificates and encryption aren't cheap). >The advantage of OOP is in its run-time nature. That is, the registry >can be modified at run-time according to anything from startup options >to real-time data input. Modifying a giant case statement (or is it a >chain of ifs? after all, URLs are not discrete in the Ada sense) might >be acceptable between deployment cycles of the given system, but >making this structure dependent on some run-time values would be too >much. Well, actually, the URL mapping (URL to key mapping is stored in a data table - of ordinary records) was intended to be a run-time data structure. I never actually implemented run-time changes for that table, but it would be simple to do so. The "requirement" that I started with is that no code outside of that known to the web server could be executed, but of course that has nothing to do with the mapping of the URLs to those existing routines. Adding a new module requires modifying the case statement, but that would require modifying a with clause and recompiling in any case. Don't see any difference there. Anyway, I think I've said everything on this topic that needs to be said. There is no one right answer to program design challenges -- only that no design at all is wrong! Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-12 4:43 ` Randy Brukardt @ 2011-08-12 7:00 ` Maciej Sobczak 2011-08-12 21:59 ` Randy Brukardt 0 siblings, 1 reply; 63+ messages in thread From: Maciej Sobczak @ 2011-08-12 7:00 UTC (permalink / raw) On Aug 12, 6:43 am, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > >I see - but isn't it a special case? > > Yes, in today's world, safety and security are surely a special case -- > hardly anyone seems to care, and thus they get PWNed all the time. > > Yes, of course there are ways to enforce safety and security in a dynamic > loading environment, Never in my posts I have mentioned dynamic loading of anything (in fact, I have always stressed that the whole program can be compiled and linked statically) and I think that your focus on safety and security in this discussion is artificial. That is, I don't see in what way OOP, applied in the way I have described, would compromise either safety or security in this kind of systems. Without this connection your "hardly anyone seems to care" is just a strawman argument. I think that everybody on this group cares about safety and security (we would not be here otherwise), we just cannot agree on how to get there while also preserving some other engineering values like flexibility of design evolution or component integration. > There is no one right answer to program design challenges Right. > -- only that no > design at all is wrong! This case was never proposed here. -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-08-12 7:00 ` Maciej Sobczak @ 2011-08-12 21:59 ` Randy Brukardt 0 siblings, 0 replies; 63+ messages in thread From: Randy Brukardt @ 2011-08-12 21:59 UTC (permalink / raw) "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message news:970ef0a5-da4b-4463-b411-aa3ef116fad1@f7g2000vba.googlegroups.com... On Aug 12, 6:43 am, "Randy Brukardt" <ra...@rrsoftware.com> wrote: >> >I see - but isn't it a special case? >> >> Yes, in today's world, safety and security are surely a special case -- >> hardly anyone seems to care, and thus they get PWNed all the time. >> >> Yes, of course there are ways to enforce safety and security in a dynamic >> loading environment, > >Never in my posts I have mentioned dynamic loading of anything (in >fact, I have always stressed that the whole program can be compiled >and linked statically) and I think that your focus on safety and >security in this discussion is artificial. Your previous message had expounded on the advantages of run-time management of modules. I had assumed that you suddenly were talking about dynamic module management, because I had already shown (twice in fact) that there was no advantage in this system to run-time management (or any other OOP characteristics) in terms of effort to add new interfaces. Perhaps you've missed a critical point: static binding should always be strongly preferred to any sort of run-time management, because it is many times easier to analyze statically (both by tools and by the programmer), it's easier to debug (because the run-time management doesn't interfere with determining what the system is actually doing), and it typically performs better (because compilers can do better optimizations, although this effect is usually marginal and is far below the importance of the first two). These are critical to program maintenance, especially when having to understand existing code (even code you wrote when you come back to it 10 years later). There has to be a strong reason for using dynamic module management: (1) The interface is complex and interrelated, so that dynamic dispatching actually buys something beyond confusion (for instance, the "action routines" of Claw for handling events); (2) Dynamic loading/reconfiguration of capabilities has to be supported; (3) Following OOP religion even when it demonstratably doesn't help is more important than the benefits of a fully static design (a so-called "object-based design"). I'd previously shown repeatedly that (1) did not apply to the web server problem (at least with the design we selected); thus I had assumed that you'd veered off into discussing (2) -- because otherwise you are simply following (3) and there is no point in discussing anything with a religious fanatic (of any stripe) -- they don't really care about facts. So at this point it is clear that we really have nothing to talk about. Sorry. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 7:55 ` Georg Bauhaus 2011-07-06 8:30 ` AdaMagica @ 2011-07-06 15:06 ` Adam Beneschan 2011-07-06 16:36 ` Dmitry A. Kazakov 2011-07-06 19:20 ` Randy Brukardt 3 siblings, 0 replies; 63+ messages in thread From: Adam Beneschan @ 2011-07-06 15:06 UTC (permalink / raw) On Jul 6, 12:55 am, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: > Instead of sprinkling the program with overriding indicators, > shouldn't it be normal for a compiler to detect the status of > a subprogram WRT overriding? To further elaborate on what Christoph said: it does detect that, and in fact you *never* need to say "overriding" or "not overriding". Using those keywords will never change the meaning of a legal program. They're there just to protect against accidental errors, which unfortunately were happening. Misspelling is one way of introducing an error. Also, there are some cases where the rules about what inherited subprograms are visible and where they're visible aren't entirely intuitive, so that in some cases even when a subprogram intended as overriding was spelled correctly, it still didn't override as intended. Errors like that don't usually lead to further syntax errors from the compiler, so it's harder to diagnose when the program doesn't run as expected. -- Adam ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 7:55 ` Georg Bauhaus 2011-07-06 8:30 ` AdaMagica 2011-07-06 15:06 ` Adam Beneschan @ 2011-07-06 16:36 ` Dmitry A. Kazakov 2011-07-06 19:20 ` Randy Brukardt 3 siblings, 0 replies; 63+ messages in thread From: Dmitry A. Kazakov @ 2011-07-06 16:36 UTC (permalink / raw) On Wed, 06 Jul 2011 09:55:44 +0200, Georg Bauhaus wrote: > On 7/6/11 6:34 AM, AdaMagica wrote: >> I should have written >> >> overriding procedure Doit (X: access Derived_Class); > > Instead of sprinkling the program with overriding indicators, > shouldn't it be normal for a compiler to detect the status of > a subprogram WRT overriding? It does. In Ada 95 there were no "overriding" qualifiers. > (It is, I think, and not just in > Ada.) Consequently, programmers would mark the opposite case. > They'd write "not overriding" only if a subprogram is really > intended to not be overriding. There are three cases actually: 1. Primitive operation 1.a. Overriding 1.b. New primitive operation 2. Free operation > - Compilers will warn in any case whenever they detect > a subprogram that looks suspicious. In order to be sure about the programmer's intent the compiler must know the class of the body being declared. Ada syntax does not provide such information, e.g. type S is new T; procedure Foo (Object : S) of T'Class; -- Overrides Foo of T'Class procedure Bar (Object : S) of S'Class; -- A new primitive operation procedure Baz (Object : S) of null; -- Free operation -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: Derived private interface 2011-07-06 7:55 ` Georg Bauhaus ` (2 preceding siblings ...) 2011-07-06 16:36 ` Dmitry A. Kazakov @ 2011-07-06 19:20 ` Randy Brukardt 3 siblings, 0 replies; 63+ messages in thread From: Randy Brukardt @ 2011-07-06 19:20 UTC (permalink / raw) "Georg Bauhaus" <rm.dash-bauhaus@futureapps.de> wrote in message news:4e141501$0$6629$9b4e6d93@newsspool2.arcor-online.net... > On 7/6/11 6:34 AM, AdaMagica wrote: >> I should have written >> >> overriding procedure Doit (X: access Derived_Class); > > Instead of sprinkling the program with overriding indicators, > shouldn't it be normal for a compiler to detect the status of > a subprogram WRT overriding? Sure, but what the compiler decides and what the programmer expects are very often different. The intent of indicators is to tell the compiler what the programmer is expecting. > (It is, I think, and not just in > Ada.) Consequently, programmers would mark the opposite case. > They'd write "not overriding" only if a subprogram is really > intended to not be overriding. That would work if the compiler rejected routines that were not overriding unless "not overriding" appears. But Ada doesn't work that way (because it inherited a bad model from Ada 95). Routines that didn't override when they were expected to cost us more than 100 hours of debugging when we building Claw. Typos, changes to the root classes, and interactions with Ada's visibility rules all caused routines to not override when they should have. Overriding indicators were invented specifically to address this problem; the original intent was to include a state where it was illegal to override unless the indicator was provided. (Semantic issues with that caused it to be abandoned.) "Not overriding" is far less important. > Premises: > - A subprogram is an overriding subprogram in most cases. > + I.e., a subprogram following a type declaration is usually > intended to override. Here, "usually" refers to OOD > being ubiquitous. That is only true for derived types (including type extensions); it's never true for any other kind of type. > - Idiomatic use will suggest to place non-overriding subprograms > in nested packages (factories, for example). That makes no sense, as any time an extension adds new operations you will want those to be primitive and inherited in further extensions. Claw has a lot of such operations. > - Compilers will warn in any case whenever they detect > a subprogram that looks suspicious. That's not possible in any reasonable way. It's quite common to add overrloaded operations with additional/different parameters in an extension. As a result, Janus/Ada has no such warnings, because we couldn't find anything that wouldn't be "crying wolf" more often than it would be telling something useful. And proper use of indicators is better anyway, because the program is rejected if wrong. Randy. ^ permalink raw reply [flat|nested] 63+ messages in thread
end of thread, other threads:[~2011-08-12 21:59 UTC | newest] Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-07-05 3:14 Derived private interface Rego, P. 2011-07-05 5:10 ` AdaMagica 2011-07-06 2:24 ` Rego, P. 2011-07-06 4:34 ` AdaMagica 2011-07-06 7:55 ` Georg Bauhaus 2011-07-06 8:30 ` AdaMagica 2011-07-06 12:59 ` Georg Bauhaus 2011-07-06 13:23 ` AdaMagica 2011-07-06 19:06 ` Randy Brukardt 2011-07-06 13:28 ` Simon Wright 2011-07-06 19:45 ` Randy Brukardt 2011-07-06 22:05 ` Georg Bauhaus 2011-07-06 23:56 ` Adam Beneschan 2011-07-07 14:09 ` Georg Bauhaus 2011-07-07 15:10 ` Adam Beneschan 2011-07-08 4:29 ` AdaMagica 2011-07-08 19:08 ` Randy Brukardt 2011-07-08 19:12 ` Randy Brukardt 2011-07-07 15:19 ` Georg Bauhaus 2011-07-07 10:37 ` Stephen Leake 2011-07-07 13:18 ` Georg Bauhaus 2011-07-08 19:23 ` Randy Brukardt 2011-07-08 21:41 ` Jeffrey Carter 2011-07-09 6:14 ` Dmitry A. Kazakov 2011-07-22 22:59 ` Randy Brukardt 2011-07-23 7:30 ` Jeffrey Carter 2011-07-23 9:29 ` Maciej Sobczak 2011-07-23 10:07 ` Dmitry A. Kazakov 2011-07-26 21:04 ` Randy Brukardt 2011-07-26 23:43 ` Jeffrey Carter 2011-07-27 23:56 ` Randy Brukardt 2011-07-28 0:18 ` Jeffrey Carter 2011-07-28 10:06 ` Maciej Sobczak 2011-07-28 23:24 ` Randy Brukardt 2011-07-29 6:45 ` Simon Wright 2011-07-30 0:04 ` Randy Brukardt 2011-07-30 6:32 ` Simon Wright 2011-08-01 9:30 ` Alex R. Mosteo 2011-08-01 10:12 ` Dmitry A. Kazakov 2011-08-01 21:56 ` Randy Brukardt 2011-08-02 10:03 ` Dmitry A. Kazakov 2011-08-02 21:16 ` Randy Brukardt 2011-08-03 9:01 ` Dmitry A. Kazakov 2011-08-03 20:16 ` Randy Brukardt 2011-08-04 8:15 ` Dmitry A. Kazakov 2011-08-09 21:10 ` Maciej Sobczak 2011-08-09 21:35 ` Randy Brukardt 2011-08-10 9:11 ` Dmitry A. Kazakov 2011-08-10 21:56 ` Randy Brukardt 2011-08-11 8:07 ` Dmitry A. Kazakov 2011-08-12 4:52 ` Randy Brukardt 2011-08-12 8:54 ` Dmitry A. Kazakov 2011-08-10 10:07 ` Maciej Sobczak 2011-08-10 11:26 ` Georg Bauhaus 2011-08-10 22:27 ` Randy Brukardt 2011-08-10 22:21 ` Randy Brukardt 2011-08-11 13:50 ` Maciej Sobczak 2011-08-12 4:43 ` Randy Brukardt 2011-08-12 7:00 ` Maciej Sobczak 2011-08-12 21:59 ` Randy Brukardt 2011-07-06 15:06 ` Adam Beneschan 2011-07-06 16:36 ` Dmitry A. Kazakov 2011-07-06 19:20 ` Randy Brukardt
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox