Teaching new tricks to an old dog (C++ -->Ada)

  • Thread starter Turamnvia Suouriviaskimatta
  • Start date
D

Dennis Lee Bieber

Ugh... Cross-posted.... And since I don't know which group
replies are being /read/ from...

I like that idea. It is possible using templates, of course. Is it general
enough? If you replace "apples" with "weight" and "oranges" with "length",
is it then permissible to multiply a length with a weight but not add the
two together?
Only if you've defined an overloaded "*" operator (and you also
have to overload for each order of arguments).

In the case of the apples/oranges, one could also create a
"FruitBasket" type, then overload

function "+"(left:apples; right:eek:ranges) return FruitBasket
and
function "+"(left:eek:ranges; right:apples) return FruitBasket

You would, inside of these overloads, have to "convert" apples
and oranges to base numeric types, do the addition on that, then
"convert" the result to FruitBasket.

For your length and weight, add a torque type, and define the
proper operator

function "*"(left:length; right:weight) return torque

--
 
M

Martin Krischik

Ioannis said:
Martin said:
Well that's easy:

unsigned int X = -1;

char Y [10];
Y [10] = "X";

Or bit more subtle:

unsigned int X Day_Of_Month = 32;
Day_Of_Month does not compile.

Shure - the X is to much - a cut/copy/paste mistake.
You can make the Day_Of_Month an enum:

Day_Of_Month - not Day_Of_Week ;-)
Bottom line is in C++ you can be as safe and as high level you like.
Just pick the suitable libraries or frameworks.

I know. But the *default* is unsave - you have to explicitly *activate*
save. While in Ada it's the other way round (yes you can deactivate save in
Ada if you need to).

Martin
 
A

Adrien Plisson

Ioannis said:
For example in .NET 2, C++ will have both its compile-time templates and
..NET's 2 run-time generics (with the keyword generic).
#include <vector>

int main()
{
using namespace std;

vector<int> somearray(10);

#pragma omp for
for(vector<int>::size_type i=0; i<somearray.size(); ++i)
somearray=i;
}


your 2 examples seems not standard C++. i don't think my favorite C++
compiler will understand "#pragma omp ..." out of the box, nor even
"generic".
In .NET you can also use its multithreading facilities, in addition to
OpenMP:
[snipped a long example of multi-threaded things relying on functions
which are not in the C++ standard]

if you had ever written any multi-threaded code in Ada, you would have
been ashamed of the example you gave.

protected Index is
procedure Set( I : Integer );
function Get return Integer;
end Index;

task Do_Something is
begin
-- use Index as you wish
end Do_Something;

task Do_Something_Else is
begin
-- use Index as you wish
end Do_Something_Else;

(the above example, does the same as your C++ example)
The are innumerable ways that you can do things in C++, you just 'plug
in" the additional facilities that you want.

additional facilities you are talking about are called "third party
libraries". any language have some, including C++ and Ada.
Do you know std::bitset?

IIRC, std::bitset is implemented in term of functions performing at
runtime the shift operations required to access a single bit.
 
A

Adrien Plisson

i just forgot some implementation details in my example. here is the
complete example:

protected Index is
procedure Set( I : Integer );
function Get return Integer;
private
Value : Integer;
end Index;

protected body Index is
procedure Set( I : Integer ) is
begin
Value := I;
end Set;

function Get return Integer is
begin
return Value;
end Get;
end Index;

task Do_Something;
task Do_Something_Else;

task body Do_Something is
begin
-- use Index as you wish
end Do_Something;

task body Do_Something_Else is
begin
-- use Index as you wish
end Do_Something_Else;
 
I

Ioannis Vranos

Pascal said:
And what about:

int main()
{
int i;
for(i=0; i<10; ++i)
;

i=7;
}

What is important for safety is not what a language permits but what
it forbids. As long as you have traps in a language you know that some
programmers will fall into it at some point.


Every variable is visible inside the scope that it was defined.

If you want to use i inside a for loop only, then define it in the for loop.


The restriction that you imply you desire, limits flexibility.

Once again, I have nothing against learning Ada, however personally I
like the most powerful languages. The next thing I am going to learn
after C++ (because I haven't learned it all yet), is probably some form
of assembly language.


For example I like that I can do:

#include <iostream>
#include <string>
#include <bitset>
#include <limits>

class SomeClass
{
std::string s;

public:
SomeClass()
{
s="This is a text message";
}
};


int main()
{
using namespace std;

SomeClass obj;

unsigned char *p= reinterpret_cast<unsigned char *>(&obj);

// Displays the individual bytes that obj
// consists of as unsigned chars.
for(unsigned i=0; i<sizeof(obj); ++i)
cout<<"character: "<<p<<"\n";

cout<<"\n";


p= reinterpret_cast<unsigned char *>(&obj);
// Displays the decimal values of the
// individual bytes that obj consists of.
for(unsigned i=0; i<sizeof(obj); ++i)
cout<<static_cast<unsigned>(p)<<" ";

cout<<"\n\n";


// Displays the bits of each byte that consist
// this SomeClass object
p= reinterpret_cast<unsigned char *>(&obj);
for(unsigned i=0; i<sizeof(obj); ++i)
{
// A byte is not necessarily 8 bits
// numeric_limits<unsigned char>::digits retrieves the number
// of byte's bits, which *is* 8 usually.
bitset<numeric_limits<unsigned char>::digits> bits(p);

for(unsigned j=0; j<bits.size(); ++j)
cout<<bits[j];

cout<<"\n";
}
}


C:\c>temp
character: â¿
character: =
character: >
character:

252 61 62 0

00111111
10111100
01111100
00000000

C:\c>


I am sure that many ADA developers will say that this one is not needed
(the ability to access the individual bytes of objects is needed in many
cases, e.g. to create low level exact copies of objects ) and it is
unsafe (yes it is, low level stuff are unsafe and it all depend on the
programmer knowing what he does).


It is up to oneself to learn whatever languages fits his purposes. For
example, a "safe" language is not an interest for me.

Someone who places much hopes on the language to protect him from his
mistakes, probably ADA is better than C++ on this.


There is no language that provides satisfies all people desires, just
because some desires are in contrast between them.
 
L

Larry Kilgallen

Ludovic Brenta wrote:


It looks like the code was not ISO C++ compliant.

In that case, it looks like the compiler failed to detect that shortcoming.
 
P

Paul E. Bennett

Ludovic said:
* when the compiler cannot check some code statically, it inserts
run-time checks which are guaranteed to catch all errors by raising
exceptions. In C++ you must code these checks by hand, and of
course at some point you'll forget one crucial check which will cost
you days in debugging.

I think the fallacy of that statement has been proven already (in a very
expensive way).


--
********************************************************************
Paul E. Bennett ....................<email://[email protected]>
Forth based HIDECS Consultancy .....<http://www.amleth.demon.co.uk/>
Mob: +44 (0)7811-639972
Tel: +44 (0)1235-811095
Going Forth Safely ....EBA. http://www.electric-boat-association.org.uk/
********************************************************************
 
L

Larry Kilgallen

I suppose you mean in the application-programming domain. But I do not
think this is true in the systems programming domain, that is efficiency
under *severe* run-time and space constraints.

And what guesswork makes you think there would be efficiency problems
with Ada ?
Also I am not sure if ADA is suitable for library writing, or you will
have to switch to another language to do that.

Huh ?

Again, what guesswork makes you suggest that ?

It is even possible in Ada to make the calling convention be the
unsafe C-style interface (null terminated strings, etc.). But for
better safety in all the languages that might call the library,
it is better to avoid those C conventions.
 
I

Ioannis Vranos

Ioannis said:
C:\c>temp
character: â¿
character: =
character: >
character:

252 61 62 0

00111111
10111100
01111100
00000000

C:\c>


Keep in mind that the code displays how things are implemented by the
specific compiler. For VC++ 2005 Express Beta 1 we get:


C:\c>cl /EHsc temp.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.41013 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

temp.cpp
Microsoft (R) Incremental Linker Version 8.00.41013
Copyright (C) Microsoft Corporation. All rights reserved.

/out:temp.exe
temp.obj

C:\c>temp
character: ♂
character: Ψ
character: A
character:
character: Ι
character: /
character: 3
character:
character: α
character:
character: B
character:
character: â–‘
character:
character: ↕
character:
character: <
character: â•¡
character: @
character:
character: â–¬
character:
character:
character:
character: â–¼
character:
character:
character:

11 150 65 0 136 47 51 0 152 8 66 0 176 255 18 0 60 181 64 0 22 0 0 0 31
0 0 0

11010000
01101001
10000010
00000000
00010001
11110100
11001100
00000000
00011001
00010000
01000010
00000000
00001101
11111111
01001000
00000000
00111100
10101101
00000010
00000000
01101000
00000000
00000000
00000000
11111000
00000000
00000000
00000000

C:\c>
 
P

Peter Koch Larsen

Larry Kilgallen said:
Which C++ compilers prevent those practices deprecated in your second
sentence ?

It is not a question of prevention. C++ allows you to do some really
dangerous things - in my mind rightfully so. When you do program in C++ you
must "constrain yourself" and not use the dangeous stuff - unless you need
to do so, of course ;-)
It's kind of like driving. You can get into a lot of trouble if you do not
follow the traffic laws (you just have to obey the physicla ones ;-), but so
long as you do driving is a fairly safe practice.

/Peter
 
P

Peter Koch Larsen

Larry Kilgallen said:
And what guesswork makes you think there would be efficiency problems
with Ada ?


Huh ?

Again, what guesswork makes you suggest that ?

It is even possible in Ada to make the calling convention be the
unsafe C-style interface (null terminated strings, etc.). But for
better safety in all the languages that might call the library,
it is better to avoid those C conventions.

It is also possible to use zero-terminated strings in C++, but every
knowledgeable person will advice that you use std::string. So what is the
difference here?

/Peter
 
I

Ioannis Vranos

Ioannis said:
and it is
unsafe (yes it is, low level stuff are unsafe and it all depend on the
programmer knowing what he does).


But it *is* portable.
 
P

Peter Koch Larsen

Ludovic Brenta said:
Most of Ada's syntax is inherited from Pascal. In fact, Ada is
"Pascal done right", since Ada eliminated most of Pascal's problems
like separate compilation or the infamous "dangling else" problem. For
that matter, these problems also exist in C and C++.

It is true that, in ISO C++, loop variables declared in the for
statement are not visible outside the loop. However, the library I
was working on did make use of the loop variable after the loop, and
none of our 4 or 5 different C++ compilers complained about it.

Which brings me to the general question: is there any
standard-compliant C++ compiler in existence? Or are compilers only
"mostly compliant" or "close enough" or some other ill-defined term?

If you disregard the controversial "export" keyword, most recent compilers
are close to being 100% conforming (but might not be so "out-of-the-box").
By contrast, consider Ada's formal validation process, which is also
an ISO standard (ISO/IEC 18009 - Ada: Conformity assessment of a
language processor). In the 1980's, the DoD held the trademark "Ada",
and only validated compilers were allowed to call themselves "Ada
compilers". Now, the rules are more lax, but all compilers in
existence pass the validation suite. See:

http://www.ada-auth.org/acats.html
I will look into that one later.
This is the crux of the problem. Assuming that the programmer "knows
the rules", "makes no mistakes" or "can be trusted" is a recipe for
disaster. One of the principles in Ada's rationale is to make
everything explicit, rather than implicit.

Do you also require parenthesis when mixing addition and multiplication? I
do not like that degree of nannying - a matter of taste, surely.
Yes:

type Weight is digits 8 range 0.0 .. 900.0; -- 8 decimal digits of
precision
type Length is digits 8 range 0.0 .. 1000.0;

Now these types are incompatible. If you want to mix them, you need
to define the semantics and provide the appropriate operators:

type Weight_Length is digits 8 range 0.0 .. 900_000.0;

function "*" (Left : in Weight; Right : in Length) return Weight_Length;

Since you don't provide "+", there is no way to add a weight to a
length.

For a more general discussion of physical quantities in Ada, see:

http://home.t-online.de/home/Christ-Usch.Grein/Ada/Universe.html

I believe I will prefer the C++ solution - a template that copes with all
this stuff.
Do you mean that not all targets may implement the requested
precision? That is true but it is not a language issue. Ada
compilers are required to document which precision they support for
their targets.

And fixed-point types being really nothing more than integers, all
targets support them to some extent.


What other mechanism would you suggest?

Termination of the program. Some might argue that they can't tolerate such
an event. But can such an environment tolerate a faulty running program?
It is a mistake to assume that the programmer makes no mistakes.
Mistakes are a given fact of the human nature. Ada is designed with
this in mind.

A sloppy programmer will avoid Ada like the plague, because they
resent discipline in general and don't appreciate being taught
lessons. A good software engineer will be attracted to Ada because
she is a powerful ally.

/Peter
 
L

Ludovic Brenta

Peter Koch Larsen said:
If you disregard the controversial "export" keyword, most recent
compilers are close to being 100% conforming (but might not be so
"out-of-the-box").

Good. What kind of assurance does a C++ compiler user have?
Do you also require parenthesis when mixing addition and
multiplication? I do not like that degree of nannying - a matter of
taste, surely.

No, just when mixing "and" and "or".
I believe I will prefer the C++ solution - a template that copes with all
this stuff.

Read the paper first; it does use templates (generics).
Termination of the program. Some might argue that they can't
tolerate such an event. But can such an environment tolerate a
faulty running program?

That's what an unhandled exception results in. In avionics, where we
have no operating system and no run-time system, exceptions cannot
propagate and thus always result in program termination. When testing
the program, we prove that no exception is ever raised.
 
L

Ludovic Brenta

Ioannis said:
The restriction that you imply you desire, limits flexibility.

Of course. That's what all these stories about shooting yourself in
the foot mean.
Once again, I have nothing against learning Ada, however personally
I like the most powerful languages. The next thing I am going to
learn after C++ (because I haven't learned it all yet), is probably
some form of assembly language.

Yes, assembly is the most powerful and flexible language. That's why
all compilers emit assembler.
For example I like that I can do:

[...]

in Ada, you would use an overlaid array of characters, like this:

with Ada.Strings.Unbounded;
with Ada.Text_IO;
procedure Unsafe_Proc is
type Some_Class is record
S : Ada.Strings.Unbounded.Unbounded_String;
end record;

Obj : aliased Some_Class :=
(S => Ada.Strings.Unbounded.To_Unbounded_String
("This is a text message"));

Obj_As_String : String (1 .. Obj'Size / System.Storage_Unit);
for Obj_As_String'Address use Obj'Address;
begin
for J in Obj_As_String'Range loop
Ada.Text_IO.Put_Line
(Integer'Image (Character'Pos (Obj_As_String (J))) &
" " &
Obj_As_String (J));
end loop;
end Unsafe_Proc;


Here, Ada makes it explicit that unsafe programming is taking place.
First, Obj must be declared as "aliased", which means that two or more
paths can access it. In our case, Obj and Obj_As_String are the two
paths. This is another of Ada's nice safety-related features. Since
aliasing must be made explicit, the reader of the program knows up
front whether or not aliasing takes place. The reader of a C++
program has no such knowledge. Also, the writer of the program must
think twice, and understand the consequences if they make an object
aliased.

Secondly, the representation clause for Obj_As_String ("for
Obj_As_String'Address use ...") says exactly what is happening.

I could make the code less verbose by using use clauses, similar to
"using namespace std" which you seem fond of. In avionics, our coding
standards forbid that because we want everything to be explicit.
I am sure that many ADA developers will say that this one is not
needed (the ability to access the individual bytes of objects is
needed in many cases, e.g. to create low level exact copies of
objects ) and it is unsafe (yes it is, low level stuff are unsafe
and it all depend on the programmer knowing what he does).

I am an Ada (not ADA) developer, and I use overlaid structures as
above in avionics software when necessary. However, Ada has better
constructs for "low-level exact copies". Ada's representation clauses
allow us to specify the bit pattern used for our low-level structures,
all the way down to endianness of numbers or absolute addresses.
It is up to oneself to learn whatever languages fits his
purposes. For example, a "safe" language is not an interest for me.

Then I am not interested entrusting my life to your software.
Someone who places much hopes on the language to protect him from
his mistakes, probably ADA is better than C++ on this.

Hear, hear!
There is no language that provides satisfies all people desires,
just because some desires are in contrast between them.

Agreed. Even in Ada, we sometimes use machine code insertions
("inline assembler") when we must.
 
I

Ioannis Vranos

Ludovic said:
Ioannis said:
The restriction that you imply you desire, limits flexibility.


Of course. That's what all these stories about shooting yourself in
the foot mean.

Once again, I have nothing against learning Ada, however personally
I like the most powerful languages. The next thing I am going to
learn after C++ (because I haven't learned it all yet), is probably
some form of assembly language.


Yes, assembly is the most powerful and flexible language. That's why
all compilers emit assembler.

For example I like that I can do:


[...]

in Ada, you would use an overlaid array of characters, like this:

with Ada.Strings.Unbounded;
with Ada.Text_IO;
procedure Unsafe_Proc is
type Some_Class is record
S : Ada.Strings.Unbounded.Unbounded_String;
end record;

Obj : aliased Some_Class :=
(S => Ada.Strings.Unbounded.To_Unbounded_String
("This is a text message"));

Obj_As_String : String (1 .. Obj'Size / System.Storage_Unit);
for Obj_As_String'Address use Obj'Address;
begin
for J in Obj_As_String'Range loop
Ada.Text_IO.Put_Line
(Integer'Image (Character'Pos (Obj_As_String (J))) &
" " &
Obj_As_String (J));
end loop;
end Unsafe_Proc;


May you provide the output of the code? Because I can not understand
much by itself. Can Ada

Then I am not interested entrusting my life to your software.


I wouldn't use low-level unsafe facilities for safety-critical
situations but types which have checks all over the place and RAII.
 
I

Ioannis Vranos

Ludovic said:
in Ada, you would use an overlaid array of characters, like this:

with Ada.Strings.Unbounded;
with Ada.Text_IO;
procedure Unsafe_Proc is
type Some_Class is record
S : Ada.Strings.Unbounded.Unbounded_String;
end record;

Obj : aliased Some_Class :=
(S => Ada.Strings.Unbounded.To_Unbounded_String
("This is a text message"));

Obj_As_String : String (1 .. Obj'Size / System.Storage_Unit);
for Obj_As_String'Address use Obj'Address;
begin
for J in Obj_As_String'Range loop
Ada.Text_IO.Put_Line
(Integer'Image (Character'Pos (Obj_As_String (J))) &
" " &
Obj_As_String (J));
end loop;
end Unsafe_Proc;


May you provide the output of the code? Because I can not understand
much by itself. Can Ada display the decimal value of each byte that
consists an object of a user-defined type, along with the bit values of
these bytes?

Then I am not interested entrusting my life to your software.


I wouldn't use low-level unsafe facilities for safety-critical
situations but types which have checks all over the place and RAII.
 
J

Jim Rogers

Once again, I have nothing against learning Ada, however personally I
like the most powerful languages. The next thing I am going to learn
after C++ (because I haven't learned it all yet), is probably some
form of assembly language.


For example I like that I can do:

#include <iostream>
#include <string>
#include <bitset>
#include <limits>

class SomeClass
{
std::string s;

public:
SomeClass()
{
s="This is a text message";
}
};


int main()
{
using namespace std;

SomeClass obj;

unsigned char *p= reinterpret_cast<unsigned char *>(&obj);

// Displays the individual bytes that obj
// consists of as unsigned chars.
for(unsigned i=0; i<sizeof(obj); ++i)
cout<<"character: "<<p<<"\n";

cout<<"\n";


p= reinterpret_cast<unsigned char *>(&obj);
// Displays the decimal values of the
// individual bytes that obj consists of.
for(unsigned i=0; i<sizeof(obj); ++i)
cout<<static_cast<unsigned>(p)<<" ";

cout<<"\n\n";


// Displays the bits of each byte that consist
// this SomeClass object
p= reinterpret_cast<unsigned char *>(&obj);
for(unsigned i=0; i<sizeof(obj); ++i)
{
// A byte is not necessarily 8 bits
// numeric_limits<unsigned char>::digits retrieves the
number // of byte's bits, which *is* 8 usually.
bitset<numeric_limits<unsigned char>::digits> bits(p);

for(unsigned j=0; j<bits.size(); ++j)
cout<<bits[j];

cout<<"\n";
}
}


C:\c>temp
character: â¿
character: =
character: >
character:

252 61 62 0

00111111
10111100
01111100
00000000

C:\c>


All this can be done in Ada.

How good is C++ at exactly representing bit fields?

Can C++ do this portably:

type Byte is mod 2**8;
type Sign_Flag is mod 2;

type Mouse_Status_Type is record
Left_Button_Pressed : Boolean;
Right_Button_Pressed : Boolean;
X_Movement_Sign : Sign_Flag;
Y_Movement_Sign : Sign_Flag;
X_Movement_Overflow : Boolean;
Y_Movement_Overflow : Boolean;
X_Movement_Magnitude : Byte;
Y_Movement_Magnitude : Byte;
end record;

for Mouse_Status_Type use record
Left_Button_Pressed at 0 range 0..0;
Right_button_Pressed at 0 range 1..1;
X_Movement_Sign at 0 range 4..4;
Y_Movement_Sign at 0 range 5..5;
X_Movement_Overflow at 0 range 6..6;
Y_Movement_Overflow at 0 range 7..7;
X_Movement_Magnitude at 1 range 0..7;
Y_Movement_Magnitude at 2 range 0..7;
end record;

The type Mouse_Status_Type defines a data
structure that occupies three bytes. The
first 6 fields of the record occupy a single
bit each, with bits 2 and 3 unused.

Furthermore, access to the individual fields of this record
are very direct, not requiring arcane bit masks.

foo : Mouse_Status_Type;


if foo.Left_Button_Pressed then
do_something;
end if;
I am sure that many ADA developers will say that this one is not
needed (the ability to access the individual bytes of objects is
needed in many cases, e.g. to create low level exact copies of objects
) and it is unsafe (yes it is, low level stuff are unsafe and it all
depend on the programmer knowing what he does).

On the contrary, Ada is frequently used for low level bit manipulation.
Ada was designed to be used in safety-critical hard real-time
embedded systems.
It is up to oneself to learn whatever languages fits his purposes. For
example, a "safe" language is not an interest for me.

We are all free to have our own interests. I do ask that you look at
the capabilities of a language before you decide they are not in your
interest. Ada does not prevent you from doing unsafe things. It
simply does not provide an unsafe behavior as its default.
Someone who places much hopes on the language to protect him from his
mistakes, probably ADA is better than C++ on this.

Programming is a human activity. All humans make mistakes. Some of those
mistakes are damned silly. Ada is designed to acknowledge that
programmers are human. Mistakes will be made. Ada attempts to identify
those mistakes as early in the development process as possible.
We all know that it is cheaper to fix mistakes early.
There is no language that provides satisfies all people desires, just
because some desires are in contrast between them.


And there is no perfect language. Ada is not meant to satisfy the
desires of all programmers. It is meant to support programming as
a human activity with the goal of producing high quality programs
very efficiently.

Jim Rogers
 
E

Ed Falis

That's what an unhandled exception results in. In avionics, where we
have no operating system and no run-time system, exceptions cannot
propagate and thus always result in program termination. When testing
the program, we prove that no exception is ever raised.


There are certainly other strategies available. For instance, in an
"integrated modular avionics" architecture, an unhandled Ada exception in
a single partition could be forwarded to a global health monitoring
facility that may restart that partition, a set of partitions, or the
whole system - or do something else for error recovery. This implies that
exception propagation is a quite flexible capability, and can be embedded
in a system with even greater error handling flexibility in a comfortable
way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,140
Latest member
SweetcalmCBDreview
Top