From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,6327f05d4989a68d X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit X-Received: by 10.181.13.205 with SMTP id fa13mr9908781wid.3.1356837414541; Sat, 29 Dec 2012 19:16:54 -0800 (PST) MIME-Version: 1.0 Path: i11ni337233wiw.0!nntp.google.com!feeder3.cambriumusenet.nl!feed.tweaknews.nl!85.12.40.131.MISMATCH!xlned.com!feeder3.xlned.com!news.astraweb.com!border6.a.newsrouter.astraweb.com!border4.nntp.ams.giganews.com!border2.nntp.ams.giganews.com!border3.nntp.ams.giganews.com!border1.nntp.ams.giganews.com!nntp.giganews.com!newsreader4.netcologne.de!news.netcologne.de!newsfeed.straub-nv.de!reality.xs3.de!news.jacob-sparre.dk!munin.jacob-sparre.dk!pnx.dk!.POSTED!not-for-mail From: "Randy Brukardt" Newsgroups: comp.lang.ada Subject: Re: Press Release - Ada 2012 Language Standard Approved by ISO Date: Wed, 26 Dec 2012 19:47:29 -0600 Organization: Jacob Sparre Andersen Research & Innovation Message-ID: References: <7wrdmbre6jw9.qww9l0uzj6mg.dlg@40tude.net> <14oqoq06zhlu2.tcasif3hdyhw.dlg@40tude.net> <1drh1q1ln2dfh$.a9hwlg01fjfy.dlg@40tude.net> <50d6365d$0$6577$9b4e6d93@newsspool3.arcor-online.net> <1pbg79bz92j3t$.sz41zduivjfp.dlg@40tude.net> <4c101d74-c8cb-45a6-82d4-91923bb950b0@googlegroups.com> <87sj6tre9s.fsf@mid.deneb.enyo.de> NNTP-Posting-Host: static-69-95-181-76.mad.choiceone.net X-Trace: munin.nbi.dk 1356572857 10466 69.95.181.76 (27 Dec 2012 01:47:37 GMT) X-Complaints-To: news@jacob-sparre.dk NNTP-Posting-Date: Thu, 27 Dec 2012 01:47:37 +0000 (UTC) X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.5931 X-RFC2646: Format=Flowed; Original X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.6157 Date: 2012-12-26T19:47:29-06:00 List-Id: wrote in message news:e9f91590-75b2-4cb4-b897-e8f06d0128e6@googlegroups.com... >This is just one programmer's opinion based on what I've seen in C++ and >Java, >but exception specifications are a bad path that goes nowhere. I strongly disagree...although they're only useful in a subset of places (not everywhere). >Consider the static case, where a subprogram has to specify a superset of >all the >specifications of subprograms it calls. This will be of limited value, >since you >almost always end up being coupled to an API that you don't have control >over >(gtkAda, Claw, etc), which are written pre-2012 and are not likely to be >updated >anytime soon. Unless they are painstakingly revised to change the default >"raises >anything" (which is not going to happen, since you cut out all pre-2012 >customers), >then all the subprograms that call them must also 'raise anything', and >those that call >those must 'raise anything' as well in a viral nature, and so on and so on >for everything, >and you end up with all subprograms raising everything, and it's a lost >cause. The >dynamic case (as in C++) is just as bad, since when an unspecified >exceptions >happens, the only thing left to do is continue erroneously or obfuscate >things by >raising a different exception than what originally happened, and you're >actually worse >off than before. Exception contracts need to be static (for the reasons you mention here), but they're absolutely needed in reusable libraries. You mentioned Claw: it has an exception contract (in the form of comments) for *every* subprogram. Raising an exception other than one in the contract is a bug, period. And that's also true for language-defined packages like Text_IO and the containers. If a routine in any such package could raise any exception for any reason, it would be impossible to use safely. The use case for exception contracts in *calling* code is not as clear -- it's possible that they ought to be avoided outside of reusable libraries. (Not sure about this.) >Secondly, the point is moot for OOP since the goal is to use classwide >types. >Putting an exception specification on a parent type automatically restricts >all the >child types (which may not even be thought of yet, much less written) to >following that same model, ... Just like using subtypes and parameter modes. Oh, the horror! :-) LSP requires that the contract of all of the child routines are the same -- if you allow child routines to raise random unknown exceptions (especially in cases that don't represent bugs - think End_Error as an example), you are violating LSP just the same as if your child routines have stronger preconditions. In which case, you can no longer reason about the class-wide calls -- greatly reducing the entire value of the OOP model. >...which is often not the case. Similar to the guideance of making the >controlling operand 'in out' to anticipate future child types that might >need >to make state changes, any parent type would be unwise to dictate what >exceptions a future child implementation might need to raise by putting >anything other than a 'raises anything'. So even if you could put perfect >exception specifications on everyting, once you start dealing with the >classwide type, it's all out the window anyway. This is terrible advice. As I mentioned last week, exceptions are used for two purposes: one is "checks", which should never fail at all. One hopes that they can be removed completely via static proof, but in any case they have to be the same (or weaker) for child routines, or else LSP is violated. The other kind is an exceptional termination, like End_Error -- and again, these have to be described as part of the contract (explicit or implicit) so that the caller can handle them approproately. You can't just go adding these to child subprograms anymore than you can add parameters (or tigher subtypes on existing parameters). Allowing exceptions to change willy-nilly is just as bad as allowing the preconditions to change that way. >Finally, IMHO, exceptions are NOT a property of the interface but of >the implementation (we will likely have to agree to disagree on this). Surely we will. No subprogram should propagate any exceptions unless they're described in the interface of the routine. Anything else is a bug (I realize most of us are lax this way). >You can take a subprogram that works one certain way (and potentially >raises one set of exceptions), and then rework the guts to work an entirely >different way but produce the same output with the same inputs, and raises >a whole new set of exceptions; e.g. if you allocate and free your variables >instead of declaring them, that changes the subprograms interface because >now you might raise STORAGE_ERROR? All subprograms can raise Storage_Error; in fact, "null;" can raise Storage_Error in Ada (formally). Storage_Error is the biggest annoyance with contracted exceptions, because it is virtually impossible to write any Ada code that does *not* have the possibility of raising Storage_Error. Thus, every exception contract will need to include it. >That's a side effect of the implementation, not a change to the interface. >Otherwise, you would have to go back and update the interface nearly every >time you change the implementation, which defeats the purpose. Propagating random exceptions from an implementation of a routine is a bug: it's either a bug because the routine isn't properly making checks internally (and thus is propagating failed checks -- one would hope that an exception contract would point out that this problem exists so that the implementation can be fixed), or because the interface isn't defined properly (to include things like Storage_Error as a possible result). >I'm of the school of thought that says every subprogram has just one >inherent contract when it comes to exceptions: as long as all the >parameters >and pre/post conditions are met, the subprogram will *never raise >anything*. >Or, to put it another way, an exception is an indication that the contract >with >the interface has NOT been met. You don't need to know which ones may >or may not be raised, since as long as you meet the pre-conditions they >won't >ever happen anyway. If you think you need an exception specification, then >IMHO what you really need is another precondition. In this case, you might as well make these the exception contracts (that is, a contract of raising nothing), because then the compiler will statically tell you when you've forgotten to make the checks or define the preconditions necessary to avoid them. Why allow runtime failures if you can ensure that they don't happen?? (I realize that the quality of proof needed to make this work might be beyond the state-of-the-art today, but I doubt that will be the case by the time a new version of Ada is defined.) The only things that should be in the exception contract are exceptions that are expected to be raised in cases that can't be statically proved: for Claw, for instance, Windows_Error is raised when Windows fails an API call; that *might* be a Claw bug or a usage bug, but it's impossible to tell in general what might cause that so we have to presume it is always possible. Note that the preconditions/predicates etc. are (formally) evaluated at the call site, and exceptions raised by them (or their failure) shouldn't be part of the subprogram's exception contract. So if the preconditions are correct, then an empty exception contract should be sufficient. (And one hopes that they can be proved.) Randy. Just my $0.02 -sb