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: 103376,fdd685ffa59d584d X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news1.google.com!news.glorb.com!news.mv.net!nntp.TheWorld.com!not-for-mail From: Robert A Duff Newsgroups: comp.lang.ada Subject: Re: What would be the Ada solution? Date: Fri, 04 Feb 2011 12:38:34 -0500 Organization: The World Public Access UNIX, Brookline, MA Message-ID: References: <0aa67233-4210-483b-b35c-8e872f87cb8f@r21g2000yqd.googlegroups.com> NNTP-Posting-Host: shell01.theworld.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: pcls6.std.com 1296841115 30806 192.74.137.71 (4 Feb 2011 17:38:35 GMT) X-Complaints-To: abuse@TheWorld.com NNTP-Posting-Date: Fri, 4 Feb 2011 17:38:35 +0000 (UTC) User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.3 (irix) Cancel-Lock: sha1:8sOGNZgPG6gKdsIUfwF73QjvLfA= Xref: g2news2.google.com comp.lang.ada:17845 Date: 2011-02-04T12:38:34-05:00 List-Id: KK6GM writes: > A colleague is working on some old code, written in C, that uses an > "out of range" integer value to indicate no valid value. Thus, a > default value (in this case 0x7FFFFFFF) means no value has been > entered. All code that uses any values should check for this no-value > and act accordingly, but of course not all the code actually does > that, and there are odd cases where the no-value value gets processed > as a valid value and then Bad Things Happen. And another problem is that you probably have lots of unnecessary/redundant checks for the no-value case. That's "defensive programming", which Bertrand Meyer wisely said is a bad idea. But it's sort of necessary in C, because it's hard to keep track of which code actually needs the checks -- better to clutter the code with redundant junk than to miss some. There are lots of ways to represent the "no valid value" value in Ada. You suggested a magic number. Mark Lorenzen suggested a variant record. Let's go with the magic number: No_Value : constant := 2**31 - 1; pragma Assert (No_Value = 16#7FFF_FFFF#); You don't want to check for No_Value all over the place. You want to check for it on input, and let the rest of your program operate on valid values, and be sure that No_Value doesn't sneak into the rest of the program. You could do something like this: type Optional_T is range -2**31 .. No_Value with Default_Value => No_Value; That means every object of subtype Optional_T will be initialized to No_Value, unless you explicitly initialize it to something else. type T is new Optional_T with Static_Predicate => T /= No_Value; That means every object of subtype T will be checked that's it's not No_Value, on assignment, parameter passing, etc. And T inherits the Default_Value. You input values of type Optional_T. You then check whether they are valid, and convert them to type T. The rest of your program is written in terms of type T. If you try to pass an Optional_T to a parameter of type T, you get a compile time error. You can convert: procedure P(X : T); Possibly_Invalid : Optional_T := Read_From_Input(...); P (T (Possibly_Invalid)); -- Might raise an exception but the conversion will raise an exception if the value is No_Value. If you declare an uninitialized variable of type T, you will get an exception, because the default value violates the predicate. If you're lucky, your compiler will warn about that at compile time. Your objects (including parameters, record components, etc) are of type T or Optional_T, so it's easy to tell which ones are safe. Hopefully, there are few Optional_T objects, and few places where you convert, so you can be careful about those. Depending on what you're trying to do, you might want to make one or both types private. If the run-time checks are too slow (which is unlikely!), you can always suppress them, and get efficiency equal to the C code. Default_Value and Static_Predicate are Ada 2012 features. Both are implemented in the latest version of GNAT, but I don't know about the public version(s). You can do more or less the same thing in Ada 2005, except that to get a default value, you have to wrap the thing in a record, and you can use range constraints instead of predicates. You could probably do more-or-less the same thing in C, but I think it would take a fair amout of horsing around. Predicates are my favorite feature of Ada 2012! And user-defined integer types are one of my favorite features of Ada 83. - Bob