Design Article
Comment
Mario Blunk
John Smith
This is a very valuable post, I found it looking through Google. I believe most ...
High-integrity object-oriented programming with Ada - Part 1
Benjamin M. Brosgol, Senior Software Engineer, AdaCore
7/20/2011 8:11 PM EDT
Three Approaches
The new guidance3 addresses this issue by defining a new concept, local type consistency verification, which ensures that class hierarchies sufficiently conform to LSP to address the vulnerability. The “local” in local type consistency refers to the fact that consistency verification can be limited to the cases that actually occur in the application. There are three approaches:
1) Formally verify substitutability; i.e., demonstrate two properties:
Although at first glance these may seem counterintuitive — specialization seems to imply the strengthening of preconditions — in fact they follow directly from the semantics of dynamic dispatch. The context of a dynamically dispatching call can only be assumed to know the pre- and post conditions for the operation as defined for the root of the inheritance hierarchy, since some of the potential subclasses might not even be written yet. If a subclass’s version of the operation strengthens the preconditions, then the call may fail because it has been written assuming the weaker preconditions and could not have anticipated new constraints such as those expressed in a strengthened precondition. An analogous situation holds with respect to post conditions.
For instance, with the formal verification approach, if an operation is never invoked through dynamic dispatch, there is no need to verify that its precondition is no stronger than its superclass’s version. This approach offers a direct verification of LSP. It is the recommended path when appropriate formal methods can be used, since they provide the highest level of confidence.
2) Ensure that each subclass passes all the tests of all its superclasses that it can replace. The second approach is well suited to verification based on unit testing. In such a context, each operation in a class is associated with a set of tests that verify its requirements. An overridden operation usually has extended requirements compared to the operation it overrides, so it will be associated with an extended set of tests. Each class can be tested separately by calling the tests of its operations. In order to use testing to verify substitutability of a given class by one of its subclasses, run all the tests for all superclasses with objects of the given subclass. If all the superclass tests pass, this provides a high degree of confidence that objects of the subclass can properly substitute for superclass objects.
3) For each dispatch point, perform pessimistic testing; i.e., test every operation that can be invoked. Pessimistic testing, may be the simplest verification method when dispatching calls are rare and the class hierarchy is shallow and/or narrow.
The developer’s approach to local type consistency verification depends on the language technology and how dynamic dispatch is used in the application. For example, formal verification is possible with some languages but not with others. In simple situations, pessimistic testing may be practical.
Static binding versus dynamic dispatch
Object oriented languages typically use the syntax v.Op(…) to indicate an operation Op applied to a polymorphic variable v. In some situations (static binding) the appropriate version of Op is identified based on the compile-time type specified in the declaration of v. In other cases (dynamic dispatch) the operation is identified based on the run-time type (class) of the object that v. denotes. If it is not clear which rule applies, this compromises readability/understandability, introducing another potential vulnerability.
Next: Operation Overriding
The new guidance3 addresses this issue by defining a new concept, local type consistency verification, which ensures that class hierarchies sufficiently conform to LSP to address the vulnerability. The “local” in local type consistency refers to the fact that consistency verification can be limited to the cases that actually occur in the application. There are three approaches:
1) Formally verify substitutability; i.e., demonstrate two properties:
- The preconditions for the subclass’s version of the operation are no stronger than those in the superclass;
- The post conditions for the subclass’s version of the operation are no weaker than those in the superclass.
Although at first glance these may seem counterintuitive — specialization seems to imply the strengthening of preconditions — in fact they follow directly from the semantics of dynamic dispatch. The context of a dynamically dispatching call can only be assumed to know the pre- and post conditions for the operation as defined for the root of the inheritance hierarchy, since some of the potential subclasses might not even be written yet. If a subclass’s version of the operation strengthens the preconditions, then the call may fail because it has been written assuming the weaker preconditions and could not have anticipated new constraints such as those expressed in a strengthened precondition. An analogous situation holds with respect to post conditions.
For instance, with the formal verification approach, if an operation is never invoked through dynamic dispatch, there is no need to verify that its precondition is no stronger than its superclass’s version. This approach offers a direct verification of LSP. It is the recommended path when appropriate formal methods can be used, since they provide the highest level of confidence.
2) Ensure that each subclass passes all the tests of all its superclasses that it can replace. The second approach is well suited to verification based on unit testing. In such a context, each operation in a class is associated with a set of tests that verify its requirements. An overridden operation usually has extended requirements compared to the operation it overrides, so it will be associated with an extended set of tests. Each class can be tested separately by calling the tests of its operations. In order to use testing to verify substitutability of a given class by one of its subclasses, run all the tests for all superclasses with objects of the given subclass. If all the superclass tests pass, this provides a high degree of confidence that objects of the subclass can properly substitute for superclass objects.
3) For each dispatch point, perform pessimistic testing; i.e., test every operation that can be invoked. Pessimistic testing, may be the simplest verification method when dispatching calls are rare and the class hierarchy is shallow and/or narrow.
The developer’s approach to local type consistency verification depends on the language technology and how dynamic dispatch is used in the application. For example, formal verification is possible with some languages but not with others. In simple situations, pessimistic testing may be practical.
Static binding versus dynamic dispatch
Object oriented languages typically use the syntax v.Op(…) to indicate an operation Op applied to a polymorphic variable v. In some situations (static binding) the appropriate version of Op is identified based on the compile-time type specified in the declaration of v. In other cases (dynamic dispatch) the operation is identified based on the run-time type (class) of the object that v. denotes. If it is not clear which rule applies, this compromises readability/understandability, introducing another potential vulnerability.
Next: Operation Overriding
Navigate to related information


EREBUS
7/21/2011 4:09 PM EDT
It is a shame that more software people did not understand or use the benefits of Ada. I understand the desire to get to the coding quickly, but from my observations over the last 30 years, you get much better software faster with Ada then you will ever get from C or C++.
A major part of this failure lies with managers who want to see instant results rather than see a well thought out software design. If you build code without a good design, you get bad software. Many managers do not understand the true issues involved with software engineering versus coding. Coding is about 5% of the job.
I really liked the real-time support built into Ada. I have seen it implemented for complex real time avionics software and it does a very good job.
Hopefully, we can get some solid Ada compilers for the microcontroller market. The cost to generate good solid firmware would be greatly reduced.
Ada is an excellent way to build software. The problem is that it requires the developers to think before they code. Sadly, most are too undisciplined to take the time to build software correctly.
Oh well, maybe someday.
Thanks
Sign in to Reply
cdhmanning
7/25/2011 10:08 PM EDT
From what I've seen, Ada is just too limited to be completely useful for general embedded development.
Ada might be good for writing some parts of the code, but not all. It is hard to partition many systems into stuff to be written in Ada and stuff that should not.
Ada seems particularly unsuited to writing device drivers, interrupt service routines and such.
You can get GNAT for ARM and even AVR.
Sign in to Reply
UncleFin
7/26/2011 10:58 AM EDT
I am not sure what "general embedded development" is, but the orgainization I belong has used Ada as the primary language for many of our avionic systems - ranging from small high integrity controllers to flight management systems.
Sign in to Reply
cdhmanning
7/27/2011 10:46 PM EDT
I can write a complete system in C, with a few lines of assembler for the start up code etc.
Can you do that in Ada? From what I've seen Ada RTEs are written in C or such because Ada isn't flexible enough.
Sign in to Reply
Powernine
10/24/2011 10:39 AM EDT
About being adequate for general and embedded development you can do in ADA what you can do in C (eg bit manipulation) except that it is safer and cleaner. You can aslo do things you cannot do in C like controlling the address a variable is stored in. In C you have to use pointers and lose all "compiler protection". In Ada you can do like that but haven't to and shouldn't to.
About RTEs the reason is because ADA vendors cut costs by using preexisting libraries and these are, unfortunately because they are a source of bugs, in C.
Sign in to Reply
Aaron451
8/4/2011 5:30 PM EDT
I used Ada '83 for several years do hard-realtime software (motor control) with great success. Now I do the same thing in 'C' and with for the Ada tools. It took a bit of time to learn, but once I got it down coding went fast and debugging was almost an after-thought. AND REAL code reuse was in the 80% range from project to project.
Sign in to Reply
Dixy3
7/21/2011 8:43 PM EDT
EREBUS, I totally agree with you, managers are always looking to cut corners to save on costs rather than have the best quality code for the job. Ada as a lot to offer given time for programmers to develop good code without additional pressure from their managers to complete the programming job like yesterday. May be it is time for someone to write a free Ada IDE for microprocessors like ARM and Arduino so developers and programmers can play at home on development boards and then start to use Ada at work in a more commercial environment? Ada I think would also be ideal for areospace nano satellites like CubeSats given the chance to develop it.
Sign in to Reply
Niklas Holsti
7/24/2011 2:59 PM EDT
Links in reply to Dixy3:
GNATDroid, a version of the GNU Ada compiler GNAT for Android: http://www.dragonlace.net/
AVR-Ada, a version of GNAT for the Atmel AVR chips: http://sourceforge.net/projects/avr-ada.
and the trump: an Ada compiler that generates C code and thus targets any system that has a C compiler: http://www.sofcheck.com/products/adamagic.html
The AdaMagic compiler is being used for a CubeSat project, I believe.
Sign in to Reply
cdhmanning
7/27/2011 11:14 PM EDT
If you really want to play, there's Ada for Lego Mindstorms robots...
http://libre.adacore.com/libre/tools/mindstorms/
Free download.
This runs on a small ARM micro and should be readily portable to other small ARM systems.
The Mindstorms Ada environment seems to use the Lejos code as its underpinnings. That is written in C.
Sign in to Reply
Ed Falis
7/26/2011 7:57 PM EDT
Here you go: http://www.cubesatlab.org/LunarLander/index.html
Sign in to Reply
John Smith
2/7/2012 5:07 AM EST
This is a very valuable post, I found it looking through Google. I believe most readers will agree with your views. Finally – a person with common sense!
http://www.zuneauto.com
Sign in to Reply
Mario Blunk
4/3/2012 9:17 AM EDT
Hi there,
I'm about to begin programming in a language other than assembly and shell programming. I'm also used to code hardware designs in Verilog HDL.
So I'm asking myself whether it is useful for me to start right with ADA and ignoring all the C/C++/Java... My mind has not been "spoiled" with this stuff :-) So what do you guys recommend ?
Sign in to Reply