comp.lang.ada
 help / color / mirror / Atom feed
* What would be the Ada solution?
@ 2011-02-04 16:33 KK6GM
  2011-02-04 16:38 ` Mark Lorenzen
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: KK6GM @ 2011-02-04 16:33 UTC (permalink / raw)


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.

I'm curious what the Ada approach to this issue would be, the issue
being to differentiate between valid and invalid values, and to catch
(compile time or run time) any manipulation of an invalid value as if
it were a valid value.



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 16:33 What would be the Ada solution? KK6GM
@ 2011-02-04 16:38 ` Mark Lorenzen
  2011-02-04 16:57 ` Robert A Duff
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Mark Lorenzen @ 2011-02-04 16:38 UTC (permalink / raw)


On 4 Feb., 17:33, KK6GM <mjsi...@scriptoriumdesigns.com> wrote:
> 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.
>
> I'm curious what the Ada approach to this issue would be, the issue
> being to differentiate between valid and invalid values, and to catch
> (compile time or run time) any manipulation of an invalid value as if
> it were a valid value.

I guess something like this:

type T is range ...;

type Opt_T (Is_Valid : Boolean := False) is
   record
      case Is_Valid is
         when True =>
            Value : T;
         when False =>
            null;
      end case;
  end record;

- Mark L



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 16:33 What would be the Ada solution? KK6GM
  2011-02-04 16:38 ` Mark Lorenzen
@ 2011-02-04 16:57 ` Robert A Duff
  2011-02-04 18:59   ` Georg Bauhaus
  2011-02-04 17:14 ` mockturtle
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Robert A Duff @ 2011-02-04 16:57 UTC (permalink / raw)


KK6GM <mjsilva@scriptoriumdesigns.com> 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.
>
> I'm curious what the Ada approach to this issue would be, the issue
> being to differentiate between valid and invalid values, and to catch
> (compile time or run time) any manipulation of an invalid value as if
> it were a valid value.

I suggest you read these two "gems":

http://www.adacore.com/2010/04/05/gem-82/
http://www.adacore.com/2010/04/05/gem-83/

- Bob



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 16:33 What would be the Ada solution? KK6GM
  2011-02-04 16:38 ` Mark Lorenzen
  2011-02-04 16:57 ` Robert A Duff
@ 2011-02-04 17:14 ` mockturtle
  2011-02-04 17:47   ` Robert A Duff
  2011-02-04 17:26 ` Dmitry A. Kazakov
  2011-02-04 17:38 ` Robert A Duff
  4 siblings, 1 reply; 9+ messages in thread
From: mockturtle @ 2011-02-04 17:14 UTC (permalink / raw)


On Friday, February 4, 2011 5:33:57 PM UTC+1, KK6GM wrote:
> 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.
> 
> I'm curious what the Ada approach to this issue would be, the issue
> being to differentiate between valid and invalid values, and to catch
> (compile time or run time) any manipulation of an invalid value as if
> it were a valid value.

A solution that I saw used somewhere

   type Extended_Values is new integer range -1 .. 1023;
   subtype Valid_Values is Extended_Values range Extended_Values'first + 1 .. Extended_values'last;
 
   No_Value : constant Extended_Values := Extended_Values'first;

A variable that should always have a valid value is declared of type Valid_Values and you should get an exception when you try to assign No_Value to it. 



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 16:33 What would be the Ada solution? KK6GM
                   ` (2 preceding siblings ...)
  2011-02-04 17:14 ` mockturtle
@ 2011-02-04 17:26 ` Dmitry A. Kazakov
  2011-02-04 17:38 ` Robert A Duff
  4 siblings, 0 replies; 9+ messages in thread
From: Dmitry A. Kazakov @ 2011-02-04 17:26 UTC (permalink / raw)


On Fri, 4 Feb 2011 08:33:57 -0800 (PST), KK6GM wrote:

> 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.
> 
> I'm curious what the Ada approach to this issue would be, the issue
> being to differentiate between valid and invalid values, and to catch
> (compile time or run time) any manipulation of an invalid value as if
> it were a valid value.

Ada solution would be to declare the integer type of the valid range:

   type ADC_16_Bit is range 0..2**16 - 1;

The compiler checks dynamically and, where possible, statically that the
value is always valid.

When values read from the hardware some bit patterns may indicate errors.
In such cases you can declare the full range of possible values and a
subrange of the valid ones:

   type ADC_Word is mod 2**16; -- 2 octets as read from the station
   Conversion_Error : constant ADC_Word := 16#FFFF#;
   Short_Circuit_Error : constant ADC_Word := 16#EFFF#;
   ...
   subtype Voltage is ADC_Word range 0..16#7FFF#; -- 0=-10V, 7FFF=+10V

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 16:33 What would be the Ada solution? KK6GM
                   ` (3 preceding siblings ...)
  2011-02-04 17:26 ` Dmitry A. Kazakov
@ 2011-02-04 17:38 ` Robert A Duff
  4 siblings, 0 replies; 9+ messages in thread
From: Robert A Duff @ 2011-02-04 17:38 UTC (permalink / raw)


KK6GM <mjsilva@scriptoriumdesigns.com> 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



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 17:14 ` mockturtle
@ 2011-02-04 17:47   ` Robert A Duff
  0 siblings, 0 replies; 9+ messages in thread
From: Robert A Duff @ 2011-02-04 17:47 UTC (permalink / raw)


mockturtle <framefritti@gmail.com> writes:

> A solution that I saw used somewhere
>
>    type Extended_Values is new integer range -1 .. 1023;
>    subtype Valid_Values is Extended_Values range Extended_Values'first + 1 .. Extended_values'last;
>  
>    No_Value : constant Extended_Values := Extended_Values'first;
>
> A variable that should always have a valid value is declared of type
> Valid_Values and you should get an exception when you try to assign
> No_Value to it.

Yes.  Or:

    type Valid_Values is range 0 .. 2**10 - 1;
    subtype Extended_Values is Valid_Values'Base range -1 .. Valid_Values'Last;

The base range is guaranteed to contain -1, because base ranges are
always symmetric about zero (usually with one extra negative value).

But these solutions involve implicit run-time checks.
Using two types instead of subtypes moves most of the
checking to compile time.

- Bob



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 16:57 ` Robert A Duff
@ 2011-02-04 18:59   ` Georg Bauhaus
  2011-02-04 19:33     ` Robert A Duff
  0 siblings, 1 reply; 9+ messages in thread
From: Georg Bauhaus @ 2011-02-04 18:59 UTC (permalink / raw)


On 04.02.11 17:57, Robert A Duff wrote:

> I suggest you read these two "gems":
> 
> http://www.adacore.com/2010/04/05/gem-82/
> http://www.adacore.com/2010/04/05/gem-83/

http://www.adacore.com/2010/03/22/gem-82/
http://www.adacore.com/2010/04/05/gem-83/


(c&p and pointers... :-)



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: What would be the Ada solution?
  2011-02-04 18:59   ` Georg Bauhaus
@ 2011-02-04 19:33     ` Robert A Duff
  0 siblings, 0 replies; 9+ messages in thread
From: Robert A Duff @ 2011-02-04 19:33 UTC (permalink / raw)


Georg Bauhaus <rm.dash-bauhaus@futureapps.de> writes:

> On 04.02.11 17:57, Robert A Duff wrote:
>
>> I suggest you read these two "gems":
>> 
>> http://www.adacore.com/2010/04/05/gem-82/
>> http://www.adacore.com/2010/04/05/gem-83/
>
> http://www.adacore.com/2010/03/22/gem-82/
> http://www.adacore.com/2010/04/05/gem-83/
>
> (c&p and pointers... :-)

Thanks for the correction!

- Bob



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-02-04 19:33 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-04 16:33 What would be the Ada solution? KK6GM
2011-02-04 16:38 ` Mark Lorenzen
2011-02-04 16:57 ` Robert A Duff
2011-02-04 18:59   ` Georg Bauhaus
2011-02-04 19:33     ` Robert A Duff
2011-02-04 17:14 ` mockturtle
2011-02-04 17:47   ` Robert A Duff
2011-02-04 17:26 ` Dmitry A. Kazakov
2011-02-04 17:38 ` Robert A Duff

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox