Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How do I write directly to a memory address?

738 views
Skip to first unread message

Syntax Issues

unread,
Feb 3, 2011, 12:52:48 AM2/3/11
to
I am planning to start learning lower-level programming with ada,
however, I was unable to find a solid tutorial on writing directly to
a memory address or interfacing with assembly. Does anyone know where
I can find a reference to some tutorials/information? Below is an
example of code I would like to be able to implement.

...
unsigned int print(char *message, unsigned int line)
{
char *vidmem = (char *) 0xb8000;
unsigned int i= 0;

i=(line*80*2);

while(*message!=0) // 24h
{
vidmem[i]= *message;
*message++;
i++;
vidmem[i]= 0x7;
i++;
};

return(1);
};
...


Georg Bauhaus

unread,
Feb 3, 2011, 3:00:24 AM2/3/11
to
On 2/3/11 6:52 AM, Syntax Issues wrote:
> I am planning to start learning lower-level programming with ada,
> however, I was unable to find a solid tutorial on writing directly to
> a memory address or interfacing with assembly. Does anyone know where
> I can find a reference to some tutorials/information? Below is an
> example of code I would like to be able to implement.

Keywords include the 'Address attribute, representations (LRM 13.3),
possibly address-to-access conversions, some details from Annex C;
many text books on Ada 95 and later will explain. A compiler
will explain how it supports machine code insertions on a given
platform.

The tutorial "Accessing memory as a string" by Robert Dewar
might be useful.

The Ada archives should, I think, have examples of writing to
DOS's video buffer.

Georg Bauhaus

unread,
Feb 3, 2011, 3:01:43 AM2/3/11
to
On 2/3/11 9:00 AM, Georg Bauhaus wrote:
> A compiler
I mean, a compiler's documentation will explain how the compiler...

mockturtle

unread,
Feb 3, 2011, 3:08:50 AM2/3/11
to
> Below is an
> example of code I would like to be able to implement.
>
> ...
> unsigned int print(char *message, unsigned int line)
> {
> char *vidmem = (char *) 0xb8000;
> unsigned int i= 0;
>

I do not have any experience about this part of Ada, but maybe I can give you a "pointer" to some bootstrapping information. Maybe you could want to use an attribute representation clause for Vidmem'Address (see Section 13.3 of the RM) . With some improvisation, I would write something like

type Vidmem_Array is array (natural range <>) of Character;
Vidmem : Vidmem_Array (0 .. Max_Size);

for Vidmem'Address use 16#000B_8000#;

Note that with this approach you need to know the maximum size of your "buffer". Otherwise, you could go through System.Address (see 13.7 and following of the RM).

As disclaimed above, I am not an expert on this, so maybe someone could want to integrate/correct/whatever the information above.

Ludovic Brenta

unread,
Feb 3, 2011, 3:24:38 AM2/3/11
to
Syntax Issues wrote on comp.lang.ada:

*Every* time I look at C code, I see a bug.
I think this is a bug; it should read "message++" since you want to
increment the pointer, not the pointed-to character.

>                 i++;
>                 vidmem[i]= 0x7;
>                 i++;
>         };
>
>         return(1);};
>
> ...

The proper way to achieve what you want is not to translate the
(buggy) C code into Ada; instead, use Ada to model the problem and
provide a clean abstraction. In this case, the model is that the
video memory, located at some address, is a two-dimensional array of
cells; each cell contains a character and an attribute byte.

type Cell_T is record
Char : Character;
Attribute : Interfaces.Unsigned_8;
end record;
pragma Pack (Cell_T);

type Horiz_Coordinate_T is mod 80;
type Vert_Coordinate_T is mod 25;
type Console_T is array
(Horiz_Coordinate_T, Vert_Coordinate_T) of Cell_T;
pragma Pack (Console_T);

Console : Console_T;
for Console'Address use 16#b8000#; -- the only low-level trick!

procedure Put (C : in Character;
Into_Console : in out Console_T;
At_X : in Horiz_Coordinate_T;
At_Y : in Vert_Coordinate_T) is
begin
Into_Console (At_X, At_Y) :=
(Char => C, Attribute => 16#7#);
end Put;


procedure Put (S : in String;
Into_Console : in out Console_T;
At_X : in Horiz_Coordinate_T;
At_Y : in Vert_Coordinate_T) is
X : Horiz_Coordinate_T := At_X;
Y : Vert_Coordinate_T := At_Y;
begin
for J in S'Range loop
Put (C => S (J),
Into_Console => Into_Console,
At_X => X,
At_Y => Y);
X := X + 1; -- modular arithmetic: wraps around
if X = 0 then
Y := Y + 1; -- ditto
end if;
end loop;
end Put;

Hope this helps

--
Ludovic Brenta.

Syntax Issues

unread,
Feb 3, 2011, 5:50:48 AM2/3/11
to

Excellent, this defiantly helps.

Georg Bauhaus

unread,
Feb 3, 2011, 6:03:59 AM2/3/11
to
On 03.02.11 09:24, Ludovic Brenta wrote:

>> unsigned int print(char *message, unsigned int line)
>> {
>> char *vidmem = (char *) 0xb8000;
>> unsigned int i= 0;
>>
>> i=(line*80*2);
>>
>> while(*message!=0) // 24h
>> {
>> vidmem[i]= *message;
>> *message++;
>
> *Every* time I look at C code, I see a bug.
> I think this is a bug; it should read "message++" since you want to
> increment the pointer, not the pointed-to character.

This is not a bug, since postfix ++ has higher precedence than *.
Indeed, *t++ = *s++; is idiomatic C.

While the result of the * operation on the pre-incremented pointer
doesn't seem to have a visible effect in this program, it still might
be intended, the intention possibly being to read the contents of
(possibly volatile) location *message, ahead of time. Who knows?
It might just as well be a c&p issue.

John McCormick

unread,
Feb 3, 2011, 12:43:49 PM2/3/11
to
On Feb 2, 11:52 pm, Syntax Issues <syntax.iss...@gmail.com> wrote:
> I am planning to start learning lower-level programming with ada,
> however, I was unable to find a solid tutorial on writing directly to
> a memory address or interfacing with assembly. Does anyone know where
> I can find a reference to some tutorials/information? Below is an
> example of code I would like to be able to implement.

Warning self promotion follows:

Chapter 2 of the book "Building Parallel, Embedded, and Real-Time
Applications with Ada" by McCormick, Singhoff, and Hugues includes a
long section on low level programming with Ada. It covers both memory
mapped and port I/O architectures. We develop polling and interrupt
based device drivers. Everything is done using high level Ada
abstractions for low level features. It includes a small amount of
machine code insertion. We just turned in the final page proofs and
expect to have hard oopy by April. See http://www.cambridge.org/gb/knowledge/isbn/item5659578

John

Jeffrey Carter

unread,
Feb 3, 2011, 1:07:24 PM2/3/11
to
On 02/03/2011 01:08 AM, mockturtle wrote:
>
> I do not have any experience about this part of Ada, but maybe I can give you
> a "pointer" to some bootstrapping information. Maybe you could want to use
> an attribute representation clause for Vidmem'Address (see Section 13.3 of
> the RM) . With some improvisation, I would write something like
>
> type Vidmem_Array is array (natural range<>) of Character; Vidmem :
> Vidmem_Array (0 .. Max_Size);
>
> for Vidmem'Address use 16#000B_8000#;

An address clause is the usual approach. If one is going to write to such
memory, one probably doesn't care what the Ada runtime might do to initialize
it, but if one is planning to read predefined information stored there, one
probably wants to prevent any initialization through a pragma Import:

pragma Import (Ada, Vidmem);

System.Address is an implementation-defined type, and an address clause takes a
value of that type. A universal integer may or may not be acceptable. Any such
code is not portable.

Other possibilities include Ada.Storage_IO (ARM A.9) and
System.Address_To_Access_Conversions (ARM 13.7.2). Masochists (such as those who
use C-family languages by choice) might want to use address arithmetic, found in
System.Storage_Elements (ARM 13.7.1).

Note that the quoted C code will happily read from memory not part of message
and write to memory not part of vidmem; Ada will not.

--
Jeff Carter
"How'd you like to hide the egg and gurgitate
a few saucers of mocha java?"
Never Give a Sucker an Even Break
101

Jeffrey Carter

unread,
Feb 3, 2011, 1:24:25 PM2/3/11
to
On 02/03/2011 01:24 AM, Ludovic Brenta wrote:
>
> *Every* time I look at C code, I see a bug.
> I think this is a bug; it should read "message++" since you want to
> increment the pointer, not the pointed-to character.

As others have explained, this is not an error, though the unused dereference is
wasted effort. However, if message does not contain zero, this will happily read
memory outside of message, and if the first zero encountered follows enough
bytes, it will happily write memory outside of vidmem.

Florian Weimer

unread,
Feb 3, 2011, 4:30:05 PM2/3/11
to
* Ludovic Brenta:

> Console : Console_T;
> for Console'Address use 16#b8000#; -- the only low-level trick!

You should also add

pragma Import (Ada, Console);

to suppress any initialization code.

Ludovic Brenta

unread,
Feb 4, 2011, 4:21:20 AM2/4/11
to
Jeffrey Carter wrote:
>> *Every* time I look at C code, I see a bug.
>> I think this is a bug; it should read "message++" since you want to
>> increment the pointer, not the pointed-to character.
>
> As others have explained, this is not an error, though the unused dereference is
> wasted effort. However, if message does not contain zero, this will happily read
> memory outside of message, and if the first zero encountered follows enough
> bytes, it will happily write memory outside of vidmem.

OK, so my hunch was wrong; there was not one but two bugs in that
line.

Funny to see that my quickly-written, untested Ada code cannot
possibly have these bugs. Proper arrays prevent reading the
terminating null character since there isn't one; the modular types
for the indexes prevent writing outside the video buffer. Once more,
praise the Lady :)

--
Ludovic Brenta.

Ludovic Brenta

unread,
Feb 4, 2011, 4:24:01 AM2/4/11
to
Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
> Syntax Issues wrote on comp.lang.ada:
>> I am planning to start learning lower-level programming with ada,
>> however, I was unable to find a solid tutorial on writing directly to
>> a memory address or interfacing with assembly. Does anyone know where
>> I can find a reference to some tutorials/information? Below is an
>> example of code I would like to be able to implement.
>
>> ...
>> unsigned int print(char *message, unsigned int line)
>> {
>>         char *vidmem = (char *) 0xb8000;
>>         unsigned int i= 0;
>>
>>         i=(line*80*2);
>>
>>         while(*message!=0) // 24h

Did I mention that *every* time I look at C code I see a bug?
Sometimes, looking twice at the same code reveals two bugs! Here you
do not check that message != NULL; the condition should be:

while (message && *message != 0)

>>         {
>>                 vidmem[i]= *message;
>>                 *message++;
>
> *Every* time I look at C code, I see a bug.
> I think this is a bug; it should read "message++" since you want to
> increment the pointer, not the pointed-to character.
>
>>                 i++;
>>                 vidmem[i]= 0x7;
>>                 i++;
>>         };
>>
>>         return(1);};

--
Ludovic Brenta.

Georg Bauhaus

unread,
Feb 4, 2011, 5:31:58 AM2/4/11
to
On 2/4/11 10:24 AM, Ludovic Brenta wrote:

>>> unsigned int print(char *message, unsigned int line)
>>> {
>>> char *vidmem = (char *) 0xb8000;
>>> unsigned int i= 0;
>>>
>>> i=(line*80*2);
>>>
>>> while(*message!=0) // 24h
>
> Did I mention that *every* time I look at C code I see a bug?
> Sometimes, looking twice at the same code reveals two bugs! Here you
> do not check that message != NULL; the condition should be:
>
> while (message&& *message != 0)

I think you won't be convincing a C programmer by stipulating that
he has been stupid and passed a null pointer for message.
He hasn't, he has thought about his program.
And it won't help promote Ada to argue that the stupid misuse
of a C function is a property of C. You are inventing contract
breaches that are equivalent to those in the style of Ariane 4/5.
Ada's type system and range checking has not prevented
programmers and engineers making a mistake.

E.g., you'd have to show a demonstration that, typically,
arrays with index subtype excluding 16 and then accessed
with value 16 have a suitable exception handler with them.
Or you'd end up talking about programmer competence, too,
and there we are, the C folks begging the question.

CVEs, as every real C programmer knows, are caused by stupid,
incompetent C programmers who should find a different occupation.

Dmitry A. Kazakov

unread,
Feb 4, 2011, 6:07:54 AM2/4/11
to
On Fri, 04 Feb 2011 11:31:58 +0100, Georg Bauhaus wrote:

> On 2/4/11 10:24 AM, Ludovic Brenta wrote:
>
>> Did I mention that *every* time I look at C code I see a bug?
>> Sometimes, looking twice at the same code reveals two bugs! Here you
>> do not check that message != NULL; the condition should be:
>>
>> while (message&& *message != 0)
>
> I think you won't be convincing a C programmer by stipulating that
> he has been stupid and passed a null pointer for message.

It might help to convince him that C is not a simple language.

> He hasn't, he has thought about his program.

Important is not "if", but "what."

> And it won't help promote Ada to argue that the stupid misuse
> of a C function is a property of C.

It is not a misuse, it is how C is used, the state of the art.

> You are inventing contract
> breaches that are equivalent to those in the style of Ariane 4/5.
> Ada's type system and range checking has not prevented
> programmers and engineers making a mistake.

I love this kind of logic: if you cannot prevent cancer, why would you
check the car brakes?

> CVEs, as every real C programmer knows, are caused by stupid,
> incompetent C programmers who should find a different occupation.

Nope, the fact is that probably no programmer is competent to use C.

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

Hyman Rosen

unread,
Feb 4, 2011, 11:00:18 AM2/4/11
to
On 2/4/2011 4:24 AM, Ludovic Brenta wrote:
> Did I mention that *every* time I look at C code I see a bug?
> Sometimes, looking twice at the same code reveals two bugs! Here you
> do not check that message != NULL; the condition should be:
> while (message&& *message != 0)

Did I mention that people who criticize C are like people
who criticize grammar? Every time they do so, their own
criticism contains errors.

You make two errors here. The first is to assume without
any actual knowledge that it is possible for the argument
to be a null pointer; it is likely that the contract for
this procedure requires that it not be. The second is that
you test for the pointer being null each time through the
loop rather than just once.

Jeffrey Carter

unread,
Feb 4, 2011, 12:35:14 PM2/4/11
to
On 02/04/2011 03:31 AM, Georg Bauhaus wrote:
> On 2/4/11 10:24 AM, Ludovic Brenta wrote:
>>
>> while (message&& *message != 0)
>
> I think you won't be convincing a C programmer by stipulating that
> he has been stupid and passed a null pointer for message.
> He hasn't, he has thought about his program.

I'm not sure this check for null is useful, but I'm not sure this is a valid
objection, either. message is incremented inside the loop. If the initial value
isn't null, it's still possible for it to be incremented until it rolls over and
becomes null. Of course, if that happens, it's a symptom of another error:
message does not contain a terminator byte.

--
Jeff Carter
"In the frozen land of Nador they were forced to
eat Robin's minstrels, and there was much rejoicing."
Monty Python & the Holy Grail
70

Dmitry A. Kazakov

unread,
Feb 4, 2011, 12:40:48 PM2/4/11
to
On Fri, 04 Feb 2011 11:00:18 -0500, Hyman Rosen wrote:

> Did I mention that people who criticize C are like people
> who criticize grammar? Every time they do so, their own
> criticism contains errors.

Right, because nobody really understands C, there is no way to reason about
C without running into errors.

> You make two errors here. The first is to assume without
> any actual knowledge that it is possible for the argument
> to be a null pointer; it is likely that the contract for
> this procedure requires that it not be. The second is that
> you test for the pointer being null each time through the
> loop rather than just once.

You just made the error of which you accused Ludovic. You assumed a
contract that the pointer cannot be modified within the loop, e.g. upon
video buffer modification.

Quality of a programming language is in great part about how close
different people could understand explicit and implied contracts when
reading the code.

Hyman Rosen

unread,
Feb 4, 2011, 1:35:14 PM2/4/11
to
On 2/4/2011 12:40 PM, Dmitry A. Kazakov wrote:
> nobody really understands C, there is no way to reason about
> C without running into errors.

C has an ISO standard which describes the language.

> You just made the error of which you accused Ludovic. You assumed a
> contract that the pointer cannot be modified within the loop, e.g. upon
> video buffer modification.

The pointer *is* modified within the loop, by incrementation.
If that pointer were situated within the video buffer itself,
the program could behave very oddly indeed, but such behavior
would almost certainly by undefined by terms of the standard
and it's unlikely that it would be "saved" by adding a check
for nullity in each iteration.

You could achieve the same oddness in Ada in the same way, by
forcing the program to place a pointer in the video buffer. In
both languages, the pointer would never be there on its own.

> Quality of a programming language is in great part about how close
> different people could understand explicit and implied contracts when
> reading the code.

The implicit contract of the subroutine is that it receives a
null-terminated string that's copied to a specified line of the
video buffer. It does no checking that the message is not null,
that the message is short enough, and that the line is within
range, so that needs to be done before the function is called.

Shark8

unread,
Feb 4, 2011, 4:36:29 PM2/4/11
to
On Feb 4, 9:00 am, Hyman Rosen <hyro...@mail.com> wrote:
> You make two errors here. The first is to assume without
> any actual knowledge that it is possible for the argument
> to be a null pointer;

As presented it is not possible to determine IF it is not
possible to pass a null-pointer in; unlike Ada, C has no null
exclusion and so cannot guarantee from the contract-that-is-
the-parameter-list that to be the case -- He MUST reason it
from the code itself making the argument dependent on the
context in which it is used. {For example, it could be a part
contained in a header-file whose original using-program DID
have the impossibility of passing NULL, but if re-used then
it may be the case that there is no such guarantee.

> it is likely that the contract for
> this procedure requires that it not be. The second is that
> you test for the pointer being null each time through the
> loop rather than just once.

This is a deficiency, IMO, of C and somewhat even Pascal;
In Ada, even w/o null-exclusion, we would likely say:
Procedure Some_Procedure( Message : Access String ) is
begin
if Message /= Null then
Declare
S : String Renames Message.All;
Begin
For Index in S'Range loop
-- whatever processing and display
End Loop;
End;
end if;
end Some_Procedure;

And within the procedure itself we capture the context which
would in the C-program and bind it directly to the procedure.
This becomes trivial with a not null access parameter.

Adam Beneschan

unread,
Feb 4, 2011, 6:00:59 PM2/4/11
to
On Feb 4, 8:00 am, Hyman Rosen <hyro...@mail.com> wrote:

> Did I mention that people who criticize C are like people
> who criticize grammar? Every time they do so, their own
> criticism contains errors.

Shouldn't that be "their own criticisms contain errors"?

-- Adam

John B. Matthews

unread,
Feb 4, 2011, 7:20:55 PM2/4/11
to
In article
<04103609-e26f-438a...@n36g2000pre.googlegroups.com>,
Adam Beneschan <ad...@irvine.com> wrote:

As required by Muphry's law:

<http://en.wikipedia.org/wiki/Muphry's_law>

--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

Randy Brukardt

unread,
Feb 5, 2011, 12:17:31 AM2/5/11
to
"Hyman Rosen" <hyr...@mail.com> wrote in message
news:4d4c477a$0$5229$882e...@usenet-news.net...
...

> The implicit contract of the subroutine is

I think I see the cause of the disagreement: there is no such thing as an
"implicit" contract. Either it is part of the explicit contract, or it
doesn't exist and it has to be checked somehow -- because programmers are
human and they *will* make mistakes or even be incompetent.

*Ada* is deficient in the ability to write proper contracts (improving this
is a primary driving force behind Ada 2012, after all), C is even worse in
this respect.

An implicit contract is the same as assuming something, and we all know what
"assume" does: it makes an "a**" of "you"and "me". :-)

Randy.


Pascal Obry

unread,
Feb 5, 2011, 9:56:06 AM2/5/11
to Hyman Rosen

Hyman,

> You make two errors here. The first is to assume without
> any actual knowledge that it is possible for the argument
> to be a null pointer; it is likely that the contract for
> this procedure requires that it not be.

I've read that a countless time. The problem is that it is not possible
to enforce a contract in C. I've seen many bugs just for that. At some
point a developer think about a contract and some time later this is
just forgotten (even if clearly written in comment, who read comments!)
and then a crash arise. Don't tell me you've never run into such situation.

Pascal.

--

--|------------------------------------------------------
--| Pascal Obry Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--| http://www.obry.net - http://v2p.fr.eu.org
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver keys.gnupg.net --recv-key F949BD3B

Simon Clubley

unread,
Feb 6, 2011, 12:49:43 PM2/6/11
to
On 2011-02-04, Ludovic Brenta <lud...@ludovic-brenta.org> wrote:
> Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
>> Syntax Issues wrote on comp.lang.ada:
>>> ...
>>> unsigned int print(char *message, unsigned int line)
>>> {
>>>         char *vidmem = (char *) 0xb8000;
>>>         unsigned int i= 0;
>>>
>>>         i=(line*80*2);
>>>
>>>         while(*message!=0) // 24h
>
> Did I mention that *every* time I look at C code I see a bug?
> Sometimes, looking twice at the same code reveals two bugs! Here you
> do not check that message != NULL; the condition should be:
>
> while (message && *message != 0)
>

That still isn't good enough unless you can guarantee that the compiler
generated code will not evaluate the second condition if the first condition
is false.

The reason is that this code will attempt to examine the contents of address
0 when message is null and on some operating systems page 0 is unmapped in
order to catch these kinds of bugs.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

Niklas Holsti

unread,
Feb 6, 2011, 1:18:23 PM2/6/11
to
Simon Clubley wrote:
> On 2011-02-04, Ludovic Brenta <lud...@ludovic-brenta.org> wrote:
>> Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
>>> Syntax Issues wrote on comp.lang.ada:
>>>> ...
>>>> unsigned int print(char *message, unsigned int line)
>>>> {
>>>> char *vidmem = (char *) 0xb8000;
>>>> unsigned int i= 0;
>>>>
>>>> i=(line*80*2);
>>>>
>>>> while(*message!=0) // 24h
>> Did I mention that *every* time I look at C code I see a bug?
>> Sometimes, looking twice at the same code reveals two bugs! Here you
>> do not check that message != NULL; the condition should be:
>>
>> while (message && *message != 0)
>>
>
> That still isn't good enough unless you can guarantee that the compiler
> generated code will not evaluate the second condition if the first condition
> is false.

That is guaranteed in C. The C "&&" operator is short-circuiting and
corresponds to the Ada "and then". The C99 standard says "If the first
operand compares equal to 0, the second operand is not evaluated."

--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .

Simon Clubley

unread,
Feb 6, 2011, 2:05:58 PM2/6/11
to

That's good to know.

However, I've used C compilers in the past when it wasn't true so I
developed a style of testing the not null condition first in a if
statement before going into the while condition.

I suspect I am not the first person whose current coding style reflects
lessons learnt from using older compilers while those problems have
subsequently been fixed in later standards. :-)

Dmitry A. Kazakov

unread,
Feb 6, 2011, 3:01:47 PM2/6/11
to
On Sun, 6 Feb 2011 19:05:58 +0000 (UTC), Simon Clubley wrote:

> I suspect I am not the first person whose current coding style reflects
> lessons learnt from using older compilers while those problems have
> subsequently been fixed in later standards. :-)

The funniest C compiler I met was under Sys.V. It modified the format
string passed to printf. The string was actually restored when formatting
was done. Alas, the very same compiler stored string literals in the
read-only memory segment!

Immutable scalar arguments still ire mutable within C and C++ subprograms.
Great ideas never die...

Maciej Sobczak

unread,
Feb 6, 2011, 4:27:05 PM2/6/11
to
On Feb 6, 9:01 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> Immutable scalar arguments still ire mutable within C and C++ subprograms.

Scalar arguments are passed by copy, so whether they are immutable or
mutable within the function is independent on their origin (and the
original is not affected by this in any way).

Unless, of course, you have meant something else.

--
Maciej Sobczak * http://www.inspirel.com

Shark8

unread,
Feb 6, 2011, 6:08:54 PM2/6/11
to

The scalar-argument that is passed when dealing with strings/arrays
[in C & C++]
is that of the address, IIRC. While that address is itself an
"immutable scalar" the
data pointed to is not so constrained and so may be 'mutated' thereby
enabling a
perceived-immutable to be altered. {The newer standards may [or may
not] have
addressed this issue: I seem to recall a "pointer to constant" idea
which would
[I believe] behave in the expected manner if it was passed as the
parameter.}

Niklas Holsti

unread,
Feb 7, 2011, 1:38:47 AM2/7/11
to
Shark8 wrote:
> On Feb 6, 2:27 pm, Maciej Sobczak <see.my.homep...@gmail.com> wrote:
>> On Feb 6, 9:01 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
>> wrote:
>>
>>> Immutable scalar arguments still ire mutable within C and C++ subprograms.
>> Scalar arguments are passed by copy, so whether they are immutable or
>> mutable within the function is independent on their origin (and the
>> original is not affected by this in any way).
>>
>> Unless, of course, you have meant something else.
>
> The scalar-argument that is passed when dealing with strings/arrays
> [in C & C++] is that of the address, IIRC. While that address is
> itself an "immutable scalar" the data pointed to is not so constrained
> and so may be 'mutated' thereby enabling a perceived-immutable to be
> altered. {The newer standards may [or may not] have addressed this
> issue: I seem to recall a "pointer to constant" idea which would
> [I believe] behave in the expected manner if it was passed as the
> parameter.}

From the C99 standard, section 6.7.5.1, "Pointer declarators":

<quote>
EXAMPLE The following pair of declarations demonstrates
the difference between a "variable pointer to a constant
value" and a "constant pointer to a variable value".

const int *ptr_to_constant;
int *const constant_ptr;

The contents of any object pointed to by ptr_to_constant
shall not be modified through that pointer, but
ptr_to_constant itself may be changed to point to another
object. Similarly, the contents of the int pointed to by
constant_ptr may be modified, but constant_ptr itself shall
always point to the same location.
<end quote>

In the first case, the protection is not removed by pointer arithmetic
or array indexing, so ptr_to_constant+8 is also a pointer to a constant
int. The constraints can be removed by "casting away" the "constant"
quality.

Shark8

unread,
Feb 7, 2011, 2:23:37 AM2/7/11
to
On Feb 6, 11:38 pm, Niklas Holsti <niklas.hol...@tidorum.invalid>
wrote:

> The constraints can be removed by "casting away" the "constant" quality.

If you can alter the constant via casting it is not truly a constant;
this is
regardless of what any standard says.* That is a HORRID idea, I for
one,
would NOT like it if my assertion "Denominator /= 0" suddenly became
"Denominator /= 3."

*In some languages a "constant" [rather literal] was a label/pointer
to the
location which held the value thereof and one could therefore "change
the
value of '4'" with some dirty-tricks/black-magic.

Niklas Holsti

unread,
Feb 7, 2011, 3:31:22 AM2/7/11
to
Shark8 wrote:
> On Feb 6, 11:38 pm, Niklas Holsti <niklas.hol...@tidorum.invalid>
> wrote:
>> The constraints can be removed by "casting away" the "constant"
>> quality.
>
> If you can alter the constant via casting it is not truly a constant;
> this is regardless of what any standard says.* That is a HORRID
> idea, I for one, would NOT like it if my assertion "Denominator /= 0"
> suddenly became "Denominator /= 3."

This is just "unchecked programming", also possible in Ada using address
clauses or address-to-access conversions. You get what you ask for. The
C cast syntax (being similar to safe kinds of type conversions) makes it
a bit hard to find such naughty tricks. The newer C++ standards have a
wider choice of cast operators that make it easier, perhaps as easy as
in Ada.

> *In some languages a "constant" [rather literal] was a label/pointer
> to the location which held the value thereof and one could therefore
> "change the value of '4'" with some dirty-tricks/black-magic.

A former colleague of mine spent a considerable time debugging a FORTRAN
IV program's wrong results before he found that a COMMON area contained,
in order, a one-dimensional array and a variable that was supposed to
hold the value of pi, as set up at program start. An assignment to the
array with an index that was too large had changed "pi" to something
else, with unfortunate consequences for later trigonometric calculations.

Unless your Ada program uses hardware (MMU) protection for its
memory-resident constants you can change the "constants" through
accesses that you get from address-to-access conversions.

Dmitry A. Kazakov

unread,
Feb 7, 2011, 3:38:53 AM2/7/11
to
On Sun, 6 Feb 2011 13:27:05 -0800 (PST), Maciej Sobczak wrote:

> On Feb 6, 9:01 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>
>> Immutable scalar arguments still ire mutable within C and C++ subprograms.
>
> Scalar arguments are passed by copy, so whether they are immutable or
> mutable within the function is independent on their origin (and the
> original is not affected by this in any way).

> Unless, of course, you have meant something else.

Exactly this. Passing mode (by copy vs. by reference) has nothing to do
with the mutability contract. Unchanged origin is no argument, because the
contract is broken [*].

Compare it to FORTRAN-IV. You can pass INTEGER*4 where REAL*4 is expected.
The original view (INTEGER*4) is not affected by the view within the
subprogram (REAL*4). Is it OK? No, lessons learned, we know this is not OK.

---------------------
* const T is not substitutable for T [almost everywhere].

Ludovic Brenta

unread,
Feb 7, 2011, 4:00:22 AM2/7/11
to
Dmitry A. Kazakov wrote:
> Immutable scalar arguments still ire mutable within C and C++ subprograms.
> Great ideas never die...

Agreed. I recently found another bug in a C program that was caused
by changing the value of a "passed-by-copy" parameter. Of course the
caller was unaffected but the algorithm inside the function was
broken.

In Ada, if you write:

procedure Foo (Arg : in Integer) is
begin
Arg := 3;
end Foo;

you get a compile-time error.

void foo (int arg) { arg = 3; }

then it "works". In the case I'm talking about, the assignment broke
an invariant inside the function, such that the function had bad side-
effects.

--
Ludovic Brenta.

Maciej Sobczak

unread,
Feb 7, 2011, 4:05:20 AM2/7/11
to
On Feb 7, 9:38 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Scalar arguments are passed by copy, so whether they are immutable or


> > mutable within the function is independent on their origin (and the
> > original is not affected by this in any way).
> > Unless, of course, you have meant something else.
>
> Exactly this. Passing mode (by copy vs. by reference) has nothing to do
> with the mutability contract. Unchanged origin is no argument, because the
> contract is broken [*].

The contract is not broken. The function cannot modify the original
value that is passed by copy (this being the very nature of "copy")
and the caller cannot even reason about what happens behind the
signature.

For example:

void foo(int i);

and then:

int i = 5;
foo(i);

The i at the caller side cannot be modified and the caller is isolated
from foo's internals. For the sake of argument, foo might be even
written in... Ada.
And for the sake of argument you can assume that this:

void foo(int i)
{
// implementation goes here
}

is equivalent to this:

procedure Foo (I : in Integer) is
Local_Copy_Of_I : Integer := I;
begin
-- implementation in terms of Local_Copy_Of_I goes here
end Foo;

So, no, the contract is not broken.

Unless, of course, you have meant something else.

--

Dmitry A. Kazakov

unread,
Feb 7, 2011, 4:24:49 AM2/7/11
to
On Mon, 7 Feb 2011 01:05:20 -0800 (PST), Maciej Sobczak wrote:

> On Feb 7, 9:38�am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>
>>> Scalar arguments are passed by copy, so whether they are immutable or
>>> mutable within the function is independent on their origin (and the
>>> original is not affected by this in any way).
>>> Unless, of course, you have meant something else.
>>
>> Exactly this. Passing mode (by copy vs. by reference) has nothing to do
>> with the mutability contract. Unchanged origin is no argument, because the
>> contract is broken [*].
>
> The contract is not broken. The function cannot modify the original
> value that is passed by copy (this being the very nature of "copy")
> and the caller cannot even reason about what happens behind the
> signature.

It is broken because const T is not substitutable for T. Mutators of the
type T are not operations of const T. q.e.d.

P.S. Contract is between two parties.

P.P.S. You may have a working program full of unstated, idiotic,
meaningless, broken contracts. This is how modern S/W industry works.

Simon Clubley

unread,
Feb 7, 2011, 7:31:29 AM2/7/11
to
On 2011-02-07, Niklas Holsti <niklas...@tidorum.invalid> wrote:

> Shark8 wrote:
>> *In some languages a "constant" [rather literal] was a label/pointer
>> to the location which held the value thereof and one could therefore
>> "change the value of '4'" with some dirty-tricks/black-magic.
>
> A former colleague of mine spent a considerable time debugging a FORTRAN
> IV program's wrong results before he found that a COMMON area contained,
> in order, a one-dimensional array and a variable that was supposed to
> hold the value of pi, as set up at program start. An assignment to the
> array with an index that was too large had changed "pi" to something
> else, with unfortunate consequences for later trigonometric calculations.
>
> Unless your Ada program uses hardware (MMU) protection for its
> memory-resident constants you can change the "constants" through
> accesses that you get from address-to-access conversions.
>

I think the "change the value of 4" reference above is literally that and
does not mean changing a language accessible constant containing the value
of 4.

I made this mistake once with a old Fortran compiler when I was a student.

The constant would be placed into a memory location somewhere by the Fortran
compiler and then that memory location would be referenced at every point in
the code in which the literal value (the integer 4 in this example) was used
in a expression or a call to a subroutine.

In my case, I assigned (IIRC) to the calling argument within the subroutine
and the memory location containing the literal value (in this example, 4)
was changed. This meant that the value of 4 was changed for the rest of
the program.

I did not make this mistake a second time. :-)

Simon Clubley

unread,
Feb 7, 2011, 7:42:35 AM2/7/11
to
On 2011-02-07, Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote:
>
> I think the "change the value of 4" reference above is literally that and
> does not mean changing a language accessible constant containing the value
> of 4.
>
> I made this mistake once with a old Fortran compiler when I was a student.
>
> The constant would be placed into a memory location somewhere by the Fortran
> compiler and then that memory location would be referenced at every point in
> the code in which the literal value (the integer 4 in this example) was used
> in a expression or a call to a subroutine.
>

I realised after posting, this was open to confusion by people who had not
encountered this before so a more detailed example follows. The word constant
above does not refer to a programmer defined constant, but a compiler defined
constant.

In the statement:

c = (4 * i) + 2

the compiler would allocate memory locations containing the values 4 and 2.
These memory locations would then be used in the generated code whenever the
values of 2 or 4 were found. In other words, all access, including literals,
was by reference.

This was a long time ago however.

Georg Bauhaus

unread,
Feb 7, 2011, 8:43:42 AM2/7/11
to
On 07.02.11 10:00, Ludovic Brenta wrote:

> In Ada, if you write:
>
> procedure Foo (Arg : in Integer) is
> begin
> Arg := 3;
> end Foo;
>
> you get a compile-time error.
>
> void foo (int arg) { arg = 3; }


In C, if you write

int foo(const int arg) {
arg = 3;
}

you will get a compile time error.

If you write

int foo(const int* arg) {
*arg = 3;
}

you will get a compile time error.

For further ammunition for Verdun style language comparisons,
see function Ada.Numerics.Discrete_Random.Random.

I think there are better arguments.

Ludovic Brenta

unread,
Feb 7, 2011, 8:56:21 AM2/7/11
to
Georg Bauhaus wrote on comp.lang.ada:

> In C, if you write
>
> int foo(const int arg) { arg = 3; }
>
> you will get a compile time error.

I know. So? The point is that the "const" was absent in the function I
had to debug, and had been absent for about 15 years. Also, not a lot
libX11 or Motif functions have "const" arguments. This bad style had
a lot of influence on the programmers of 15 years ago whose code I
must now maintain.

In Ada, this bad style is simply not possible. In Ada, "in" really
means "in".

> If you write
>
> int foo(const int* arg) { *arg = 3; }
>
> you will get a compile time error.

I know but bugs are easier to detect because when reviewers see a
pointer argument, they know they have to look out for writes through
the pointer. Even if the pointer is to a "const", since it is
trivially easy to defeat the const-ness.

> For further ammunition for Verdun style language comparisons,
> see function Ada.Numerics.Discrete_Random.Random.

What does that mean?

> I think there are better arguments.

No. There was an old (because difficult to reproduce) bug. I spent
time finding and correcting it. This bug could not have happened in
Ada. This argument is the only relevant one to me.

--
Ludovic Brenta.

Hyman Rosen

unread,
Feb 7, 2011, 9:59:16 AM2/7/11
to
On 2/5/2011 9:56 AM, Pascal Obry wrote:
> The problem is that it is not possible to enforce a contract in C.
> I've seen many bugs just for that. At some point a developer think
> about a contract and some time later this is just forgotten (even
> if clearly written in comment, who read comments!) and then a crash
> arise. Don't tell me you've never run into such situation.

I have. Nevertheless, there is an enormous amount of successfully
operating C code in existence, and such code is not sprinkled with
checks at every opportunity. I have a hunch that the urge to focus
on pointer-related errors is something that Ada programmers like to
do because it's a class of bugs to which Ada is generally immune,
and so they can scan C code for pointers and claim that unchecked
ones are all potential errors. But there are plenty of contracts
which cannot be enforced just by using the type system, and I venture
that most Ada code does not include checks for violations in every
context in which the contract is presumed to hold. And is Ada any
more immune than C to little Bobby Tables? (<http://xkcd.com/327/>)

Georg Bauhaus

unread,
Feb 7, 2011, 9:58:44 AM2/7/11
to
On 07.02.11 14:56, Ludovic Brenta wrote:

> This bad style had
> a lot of influence on the programmers of 15 years ago whose code I
> must now maintain.

Exactly. Style has, by hypothesis, a strong impact on on code
quality, since programming patterns and programming idioms are
passed on at every stage of becoming outdated. Programmers will
copy idioms with little consideration, especially when idioms
have become associated with revered authors, first edition.
They are not updated. They are also not updated because
compilers will not reject old code.


> In Ada, this bad style is simply not possible.

It sure is possible to write awful and dangerous Ada text, even
with the dangers hidden. While this style is possible, Ada culture
is less tolerant. (Or, more skeptical of the "practical" programmer.)


> In Ada, "in" really means "in".

No, "in" is intended to mean "in". There are two reasons that
this is not an unbreakable property. The first is demonstrated by
Ada.Numerics.Discrete_Random.Random.
But Random is the exception rather than the rule, Ada tradition
promotes the reverse effect of what C tradition promotes, I think:
by Ada's default, by the traditional idiom, "in" stands for "in".
(In the case of void safety, the language discussions include
comments bemoaning that we'll have to write "not null"
instead of marking the reverse case (may be null), thus underlining
the tradition.)

The second reason that "in" need not mean "in" is less brutal:
it is the possibility of write access to a parameter object
from within the function if the objects is also a global object.
(Global to the function). (Whence Ada getting "in out" parameters
for functions is considered an act of honesty, if I understand
comment in ARG mail correctly.) Again, this kind of access is
considered by style (and is also possible in C).


>> For further ammunition for Verdun style language comparisons,
>> see function Ada.Numerics.Discrete_Random.Random.
>
> What does that mean?

It means that Ada function Ada.Numerics.Discrete_Random.Random
only works because it violates its "contract". The parameter (a
generator object) is passed "in", but is modified. Its mutation
is one effect of calling function Random.


>> I think there are better arguments.
>
> No.

Yes, and you have named them. They seem to have a little less
to do with the language definitions, but rather with "encouragement"
to write your intentions properly.
(In at least one video (lecture? Ada UK?) Robert Dewar
has been emphasizing a cultural issue a few times).

Dmitry A. Kazakov

unread,
Feb 7, 2011, 10:21:37 AM2/7/11
to
On Mon, 07 Feb 2011 15:58:44 +0100, Georg Bauhaus wrote:

> No, "in" is intended to mean "in". There are two reasons that
> this is not an unbreakable property. The first is demonstrated by
> Ada.Numerics.Discrete_Random.Random.

This is a poor example, because random number is indeed immutable and has
no intrinsic state. A pseudo-random generator has state, but the thing it
models is stateless. In this sense there is no difference between integer
123 and the random number uniformly distributed on [0,1]. In both cases the
corresponding computational object might have state or not. E.g. literal
can be stored in the volatile memory. Whether such implementation detail
need to be exposed (to have Reset, for example), depends on many factors.
See also Ada.Calendar.Clock.

> It means that Ada function Ada.Numerics.Discrete_Random.Random
> only works because it violates its "contract". The parameter (a
> generator object) is passed "in", but is modified. Its mutation
> is one effect of calling function Random.

Wrong. You might have an implementation of Random backed by the hardware in
which case Random would have no internal state whatsoever.

Robert A Duff

unread,
Feb 7, 2011, 11:14:29 AM2/7/11
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> Wrong. You might have an implementation of Random backed by the hardware in
> which case Random would have no internal state whatsoever.

I don't think a truly random implementation of
Ada.Numerics. ... .Random would be correct,
because you're allowed to reset the state to a
previously-saved state, and replay they exact same sequence
of pseudo-random numbers.

It might be useful to have a truly-random function, but
it would have to be a different one.

- Bob

Robert A Duff

unread,
Feb 7, 2011, 11:24:00 AM2/7/11
to
Hyman Rosen <hyr...@mail.com> writes:

>...And is Ada any


> more immune than C to little Bobby Tables? (<http://xkcd.com/327/>)

Well, yeah, somewhat. As I mentioned in another thread:

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

The second "gem" contains a reference to that very
same xkcd comic you mention above (which I found
highly amusing!).

Similar things could be done in C, but it's it's rather
more trouble.

- Bob

Hyman Rosen

unread,
Feb 7, 2011, 11:44:56 AM2/7/11
to

I don't think you've made your case. The gem says
As long as this interface is used, no errors can result
in improper input being interpreted as a command
but SQL injection problems occur because at some point,
a programmer fails to notice that there's an input that
needs to be subject to the check.

By the way, I think the gem is taking the wrong approach to
validation. There's no reason to reject strings with special
characters as invalid input. Building up SQL with user inputs
involves correctly quoting the inputs. When they're properly
quoted they can have embedded special characters and the SQL
will still be correct. Otherwise you subject users to annoying
restrictions such as not allowing those characters in their
passwords.

Ludovic Brenta

unread,
Feb 7, 2011, 11:54:01 AM2/7/11
to
Georg Bauhaus wrote:
> Exactly.  Style has, by hypothesis, a strong impact on on code
> quality [...]

I would rephrase that as: style has, *in my experience*, a strong
impact on code quality.

>> In Ada, this bad style is simply not possible.
>
> It sure is possible to write awful and dangerous Ada text, even
> with the dangers hidden.  While this style is possible, Ada culture
> is less tolerant. (Or, more skeptical of the "practical" programmer.)

In Ada, it is pretty difficult to hide such dangers. In the case I
was talking about, had the subprogram been written in Ada, the
programmer would have had to declare a copy of the "in" argument
explicitly or to make the argument "in out"; both would have made the
bug immediately obvious to any reviewer. The reason why the bug
eluded so many people and survived 15 years was that reviewers failed
to see the assignment as the cause for the bug. Perhaps because they
were tainted by Ada culture where, if you assign to an argument, this
necessarily means the argument is "in out".

You can always program dangerously in Ada but you have to be explicit
about it.

>>> For further ammunition for Verdun style language comparisons,
>>> see function Ada.Numerics.Discrete_Random.Random.
>
>> What does that mean?
>
> It means that Ada function Ada.Numerics.Discrete_Random.Random
> only works because it violates its "contract".  The parameter (a
> generator object) is passed "in", but is modified. Its mutation
> is one effect of calling function Random.

The generator is not modified; its associated (pointed-to) state is.
When reviewing a function that takes a pointer (or an object
containing a pointer), I expect and look for writes through the
pointer, so again the bug I was talking about would not have survived
a code review.

>>> I think there are better arguments.
>
>> No.
>
> Yes, and you have named them.  They seem to have a little less
> to do with the language definitions, but rather with "encouragement"
> to write your intentions properly.
> (In at least one video (lecture? Ada UK?) Robert Dewar
> has been emphasizing a cultural issue a few times).

Well, I came to wonder what intentions are conveyed by "void foo (int
arg)" and why modifying arg inside foo could be intentional. Since I
came up with no convincing reason (the only reasons being variants of
premature optimization), I concluded that the possibility of "void foo
(int arg)" as opposed to "void foo (const int arg)" was a flaw in the
C language, that cost me a lot of effort.

--
Ludovic Brenta.

Ludovic Brenta

unread,
Feb 7, 2011, 12:02:19 PM2/7/11
to
Hyman Rosen wrote on comp.lang.ada:

> On 2/7/2011 11:24 AM, Robert A Duff wrote:
>> Hyman Rosen<hyro...@mail.com>  writes:

I've always wondered what this "SQL sanitation" was all about. Aren't
we supposed to pass all user input as bound parameters anyway? That
even removes the need for quoting.

--
Ludovic Brenta.

Dmitry A. Kazakov

unread,
Feb 7, 2011, 12:23:10 PM2/7/11
to

You are right.

Georg Bauhaus

unread,
Feb 7, 2011, 12:55:09 PM2/7/11
to
On 07.02.11 17:54, Ludovic Brenta wrote:
> Georg Bauhaus wrote:
>> Exactly. Style has, by hypothesis, a strong impact on on code
>> quality [...]
>
> I would rephrase that as: style has, *in my experience*, a strong
> impact on code quality.

That's something from which to start an investigation.

> You can always program dangerously in Ada but you have to be explicit
> about it.

Yes.


> The generator is not modified; its associated (pointed-to) state is.

The state is "its" state; the LRM does not seem to mention
a pointer. GNAT uses a limited record with no pointers in
it, but does refer to components through non-standard
'Unrestricted_Access inside the function.

GNAT: "
-- The design of this spec is very awkward, as a result of Ada 95 not
-- permitting in-out parameters for function formals (most naturally
-- Generator values would be passed this way). "

I think it is fair to say that (a) Random modifies the generator's
state and that (b) the specification does not reflect that Random
acts as this state changing subprogram.


> Well, I came to wonder what intentions are conveyed by "void foo (int
> arg)" and why modifying arg inside foo could be intentional. Since I
> came up with no convincing reason (the only reasons being variants of
> premature optimization), I concluded that the possibility of "void foo
> (int arg)" as opposed to "void foo (const int arg)" was a flaw in the
> C language, that cost me a lot of effort.

Ease of implementation when pushing parameters?


void foo(int countdown)
{
while (--countdown) {
fputc('.', stdout);
}
fputc('\n', stdout);
}

Georg Bauhaus

unread,
Feb 7, 2011, 1:10:12 PM2/7/11
to
On 07.02.11 16:21, Dmitry A. Kazakov wrote:

>> It means that Ada function Ada.Numerics.Discrete_Random.Random
>> only works because it violates its "contract". The parameter (a
>> generator object) is passed "in", but is modified. Its mutation
>> is one effect of calling function Random.
>
> Wrong. You might have an implementation of Random backed by the hardware in
> which case Random would have no internal state whatsoever.

An implementation does not specify the language. By the language,
Random relies on the fact that whenever it is finished, it will
deliver the "next" value ("from its generator"). The state of a
Generator can be saved and restored, so the notion of its state
is meaningful in the abstract.
Since we are discussion the effects of subprogram specs on programmer
intuition, Random's parameter Gen being of mode "in" is at odds with
the usual meaning of "in".


Jeffrey Carter

unread,
Feb 7, 2011, 1:38:06 PM2/7/11
to
On 02/07/2011 09:14 AM, Robert A Duff wrote:
>
> I don't think a truly random implementation of
> Ada.Numerics. ... .Random would be correct,
> because you're allowed to reset the state to a
> previously-saved state, and replay they exact same sequence
> of pseudo-random numbers.
>
> It might be useful to have a truly-random function, but
> it would have to be a different one.

I suppose you could save the sequence of values returned so far, and the state
would be an index into that sequence.

--
Jeff Carter
"We burst our pimples at you."
Monty Python & the Holy Grail
16

Simon Wright

unread,
Feb 7, 2011, 2:27:38 PM2/7/11
to
Georg Bauhaus <rm.dash...@futureapps.de> writes:

> Since we are discussion the effects of subprogram specs on programmer
> intuition, Random's parameter Gen being of mode "in" is at odds with
> the usual meaning of "in".

Likewise Ada.Text_IO --

procedure Set_Page_Length (File : File_Type; To : Count);

as a particularly "wrong" example. But see AI95-00057:
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ais/ai-00057.txt?rev=1.6
(practicality wins over purity).

Dmitry A. Kazakov

unread,
Feb 7, 2011, 2:29:56 PM2/7/11
to
On Mon, 07 Feb 2011 19:10:12 +0100, Georg Bauhaus wrote:

> On 07.02.11 16:21, Dmitry A. Kazakov wrote:
>
>>> It means that Ada function Ada.Numerics.Discrete_Random.Random
>>> only works because it violates its "contract". The parameter (a
>>> generator object) is passed "in", but is modified. Its mutation
>>> is one effect of calling function Random.
>>
>> Wrong. You might have an implementation of Random backed by the hardware in
>> which case Random would have no internal state whatsoever.
>
> An implementation does not specify the language. By the language,
> Random relies on the fact that whenever it is finished, it will
> deliver the "next" value ("from its generator"). The state of a
> Generator can be saved and restored, so the notion of its state
> is meaningful in the abstract.

That is specific to the procedure Reset, which is not essential for random
number generation.

> Since we are discussion the effects of subprogram specs on programmer
> intuition, Random's parameter Gen being of mode "in" is at odds with
> the usual meaning of "in".

Not at all. It is Reset, which probably is. Random is perfectly OK.

Robert A Duff

unread,
Feb 7, 2011, 4:38:27 PM2/7/11
to
Jeffrey Carter <spam.jrc...@spam.not.acm.org> writes:

> I suppose you could save the sequence of values returned so far, and the
> state would be an index into that sequence.

Good point.

I guess the state would be the whole sequence, plus
an index into it, or something like that.

- Bob

Randy Brukardt

unread,
Feb 7, 2011, 4:54:18 PM2/7/11
to
"Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in
message news:iiopbr$bs7$1...@news.eternal-september.org...
...

> I realised after posting, this was open to confusion by people who had not
> encountered this before so a more detailed example follows. The word
> constant
> above does not refer to a programmer defined constant, but a compiler
> defined
> constant.

You mean a numeric literal (to use the Ada terms).

> In the statement:
>
> c = (4 * i) + 2
>
> the compiler would allocate memory locations containing the values 4 and
> 2.
> These memory locations would then be used in the generated code whenever
> the
> values of 2 or 4 were found. In other words, all access, including
> literals,
> was by reference.
>
> This was a long time ago however.

Must have been. I remember hearing this story in college. And it supposely
was old then. I've always thought of it as a sort of urban legend. But I
suspect that it has more to do with the instruction set of the target
machine. On the Intel architectures that I've worked on my entire working
life, it wouldn't make sense to have a global memory location holding a
literal (the literals can be folded into instructions at very little cost).
But I can imagine cases where that wouldn't be true.

Randy.


Simon Wright

unread,
Feb 7, 2011, 5:41:29 PM2/7/11
to

I don't think this would meet A.5.2(28), "[...] All generators are
implicitly initialized to an unspecified state that does not vary from
one program execution to another[...]".

I suppose that (reverting to the current Numerics.Discrete_Random) means
"for the same compiler on the same architecture"? You could hardly
expect GCC 4.3.3 on PowerPC to produce the same output as GCC 4.6.0 on
x86_64. Or could it even mean "for executions of a specific build of a
specific program on a specific machine"?

Maciej Sobczak

unread,
Feb 7, 2011, 6:11:23 PM2/7/11
to
On Feb 7, 10:24 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > The contract is not broken. The function cannot modify the original


> > value that is passed by copy (this being the very nature of "copy")
> > and the caller cannot even reason about what happens behind the
> > signature.
>
> It is broken because const T is not substitutable for T. Mutators of the
> type T are not operations of const T. q.e.d.

q.e.d. what?

I have an impression that we are (again) in the mode where you bring
arbitrarily twisted definitions in order to prove your point.

What contract is broken?

Why do you want to substitute one type by another? These are not
generics, nor other type-dependent constructs, so type substitutions
are out of the picture.

Or (because I have no idea what is your point, so I'm guessing), you
can easily use const T to provide the actual value for the parameter
of T:

void foo(int i);

and then:

const int j = 7;
foo(j);

Type substitution does not happen here. The types interact by means of
initialization, but this interaction has nothing to do with
substitution.

So, no contract is broken. (q.e.d.?)

Unless, of course, you have meant something else.

--

Bill Findlay

unread,
Feb 7, 2011, 7:21:37 PM2/7/11
to
On 07/02/2011 21:54, in article iippmb$q45$1...@munin.nbi.dk, "Randy Brukardt"
<ra...@rrsoftware.com> wrote:

> I remember hearing this story in college. And it supposely was old then.
> I've always thought of it as a sort of urban legend.

I had to debug a FORTRAN 66 program (my own, sadly, written in 1967) that
was going astray in a statement of the form:

IF (X) 101, 102, 103

The problem was that a previous call to a library subroutine, along the
lines of:

CALL SOLVE(A, X, B, 0.0)

was updating the accuracy parameter 0.0 to the residual norm of the solution
(or some such accuracy indication), and this was making the implicit
comparison with 0.0 in the later IF statement go wrong.

--
Bill Findlay
with blueyonder.co.uk;
use surname & forename;


Adam Beneschan

unread,
Feb 7, 2011, 8:06:06 PM2/7/11
to
On Feb 7, 1:54 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> "Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in
> messagenews:iiopbr$bs7$1...@news.eternal-september.org...

I think C was originally designed for the PDP-11. It's been ages
since I did anything with that processor, but my recollection is that
you could include a 16-bit numeric literal in an instruction. It
would take up an extra word, but putting the literal somewhere else
and including the address in the instruction would also take up an
extra word, so you wouldn't save anything. However, if the literal
needed to be 32 bits then I can imagine it might have made sense to
stick it in a global.

-- Adam

Ludovic Brenta

unread,
Feb 8, 2011, 3:04:18 AM2/8/11
to
Georg Bauhaus wrote:
>> Well, I came to wonder what intentions are conveyed by "void foo (int
>> arg)" and why modifying arg inside foo could be intentional.  Since I
>> came up with no convincing reason (the only reasons being variants of
>> premature optimization), I concluded that the possibility of "void foo
>> (int arg)" as opposed to "void foo (const int arg)" was a flaw in the
>> C language, that cost me a lot of effort.
>
> Ease of implementation when pushing parameters?
>
> void foo(int countdown)
> {
>   while (--countdown) {
>     fputc('.', stdout);
>   }
>   fputc('\n', stdout);
> }

That's what I meant by "variants of premature optimization". If all
parameters were const, as in Ada, the programmer would simply declare
a local variable, like in Ada. And the bug I was talking about would
become blatantly obvious.

BTW, like I said, *every* time I look at C code, I see a bug. In your
case, foo has undefined behavior if countdown is negative.

Also, note how the Ada version of this function does not use a
variable at all; it uses a for loop inside of which K is constant. And
it does not have your bug:

procedure Foo (Countdown : in Natural) is
begin
for K in 1 .. Countdown loop
Put ('.');
end loop;
Next_Line;
end Foo;

So, "ease of implementation" is not a good reason. The thing you
implemented "easily" had a bug.

--
Ludovic Brenta.

Nasser M. Abbasi

unread,
Feb 8, 2011, 4:01:59 AM2/8/11
to
On 2/8/2011 12:04 AM, Ludovic Brenta wrote:
> Georg Bauhaus wrote:
>>> Well, I came to wonder what intentions are conveyed by "void foo (int
>>> arg)" and why modifying arg inside foo could be intentional. Since I
>>> came up with no convincing reason (the only reasons being variants of
>>> premature optimization), I concluded that the possibility of "void foo
>>> (int arg)" as opposed to "void foo (const int arg)" was a flaw in the
>>> C language, that cost me a lot of effort.
>>
>> Ease of implementation when pushing parameters?
>>
>> void foo(int countdown)
>> {
>> while (--countdown) {
>> fputc('.', stdout);
>> }
>> fputc('\n', stdout);
>> }
>
>

>


> BTW, like I said, *every* time I look at C code,

This is funny, but I understand what you mean.

> I see a bug. In your
> case, foo has undefined behavior if countdown is negative.
>

If I remember my C, since "while" will keep running until its argument
becomes false, which in C means "zero", then this means if countdown is
negative the above code will keep decrementing countdown until it hits
-infinity? :) and the program will crash or do something else?



> Also, note how the Ada version of this function does not use a
> variable at all; it uses a for loop inside of which K is constant. And
> it does not have your bug:
>
> procedure Foo (Countdown : in Natural) is
> begin
> for K in 1 .. Countdown loop
> Put ('.');
> end loop;
> Next_Line;
> end Foo;
>
> So, "ease of implementation" is not a good reason. The thing you
> implemented "easily" had a bug.
>
> --
> Ludovic Brenta.

Ada has so many nice things in it. I think its type system is one
of the best features of Ada.

--Nasser

Ludovic Brenta

unread,
Feb 8, 2011, 4:08:25 AM2/8/11
to
Nasser M. Abbasi wrote on comp.lang.ada:

>> Georg Bauhaus wrote:
>>> void foo(int countdown)
>>> {
>>>    while (--countdown) {
>>>      fputc('.', stdout);
>>>    }
>>>    fputc('\n', stdout);
>>> }
>
>> BTW, like I said, *every* time I look at C code,
>
> This is funny, but I understand what you mean.
>
>> I see a bug. In your
>> case, foo has undefined behavior if countdown is negative.
>
> If I remember my C, since "while" will keep running until its argument
> becomes false, which in C means "zero", then this means if countdown is
> negative the above code will keep decrementing countdown until it hits
> -infinity? :) and the program will crash or do something else?

Actually, the bug also triggers if countdown == 0 upon entry into foo,
because of the *prefix* decrement operator.

The behavior is undefined by the language but most C programmers
assume that counter will wrap around. In fact, when GCC 4.5
introduced aggressive optimizations based on the knowledge that
overflow semantics was undefined in C, a *lot* of existing programs
were suddenly broken. In fact, only their incorrect assumptions
("hidden contracts") were broken. The damage was so severe that the
GCC folks had to demote this aggressive optimization to a non-default
compiler switch :(

--
Ludovic Brenta.

Georg Bauhaus

unread,
Feb 8, 2011, 4:43:03 AM2/8/11
to
On 2/8/11 9:04 AM, Ludovic Brenta wrote:

>> void foo(int countdown)
>> {
>> while (--countdown) {
>> fputc('.', stdout);
>> }
>> fputc('\n', stdout);
>> }
>
> That's what I meant by "variants of premature optimization".

See why Ada cannot be efficient? ;-)

Georg Bauhaus

unread,
Feb 8, 2011, 4:46:18 AM2/8/11
to
On 2/8/11 9:04 AM, Ludovic Brenta wrote:

>> Ease of implementation when pushing parameters?
>>
>> void foo(int countdown)
>> {
>> while (--countdown) {
>> fputc('.', stdout);
>> }
>> fputc('\n', stdout);
>> }
>
> That's what I meant by "variants of premature optimization". If all
> parameters were const, as in Ada, the programmer would simply declare
> a local variable, like in Ada. And the bug I was talking about would
> become blatantly obvious.

As I said, maybe that was easier to implement for the
C language and compiler makers.

You'd have to demonstrate that an Ada procedure, needing
an extra loop variable, will produce the same code.
(Hopefully, it does not!)

> BTW, like I said, *every* time I look at C code, I see a bug. In your
> case, foo has undefined behavior if countdown is negative.

We are playing Monopoly, aren't we. You won't be winning a
single C programmer with this style of non-framed single
issue logic triggered only by stupid misuse of a perfectly
working solution.

As Hyman said, there are tons of well working C programs out there,
very likely using some int i, plus increment or decrement.

Well, there is a related CVE every other week, but (a) there
aren't equally many Ada programs, (b) if programmers don't know
what INT_MAX + 1 is, they shouldn't be programming in C, and
(c) by single case logic, Ada's type system has not prevented
deaths in Ariane 5 anyway.

Ludovic Brenta

unread,
Feb 8, 2011, 4:58:43 AM2/8/11
to
Georg Bauhaus wrote:
> On 2/8/11 9:04 AM, Ludovic Brenta wrote:
>>> Ease of implementation when pushing parameters?
>
>>> void foo(int countdown)
>>> {
>>>    while (--countdown) {
>>>      fputc('.', stdout);
>>>    }
>>>    fputc('\n', stdout);
>>> }
>
>> That's what I meant by "variants of premature optimization".  If all
>> parameters were const, as in Ada, the programmer would simply declare
>> a local variable, like in Ada.  And the bug I was talking about would
>> become blatantly obvious.
>
> As I said, maybe that was easier to implement for the
> C language and compiler makers.

Yes. This is the root cause why C is so bad for everyone else.

> You'd have to demonstrate that an Ada procedure, needing
> an extra loop variable, will produce the same code.
> (Hopefully, it does not!)

Hopefully, it does, except for the precondition check that Countdown
>= 0.

>> BTW, like I said, *every* time I look at C code, I see a bug. In your
>> case, foo has undefined behavior if countdown is negative.
>
> We are playing Monopoly, aren't we.  You won't be winning a
> single C programmer with this style of non-framed single
> issue logic triggered only by stupid misuse of a perfectly
> working solution.

I don't know what you mean with Monopoly but, if I were trying to win
over C programmers, I'd be on comp.lang.c right now. And this is
*not* "stupid misuse of a perfectly working solution", it is strict
interpretation of the explicit contract that you yourself had
provided: the function "foo" accepts a *signed* integer as its
parameter. The "stupid misuse" is yours; you should have used
"unsigned int" to express your contract, and then accounted for the
possibility that the parameter could be zero.

> As Hyman said, there are tons of well working C programs out there,
> very likely using some int i, plus increment or decrement.

And the majority of these tons of "working" programs were broken the
instant GCC started to optimize overflows away.

> Well, there is a related CVE every other week, but (a) there
> aren't equally many Ada programs, (b) if programmers don't know
> what INT_MAX + 1 is, they shouldn't be programming in C, and

Ah that's a good one. It is perfectly true. It is well known that C
was created only for perfect programmers who never make mistakes. But
these programmers, if they exist, do not need C; they can simply "cat
> a.out", can't they?

> (c) by single case logic, Ada's type system has not prevented
> deaths in Ariane 5 anyway.

Huh?

--
Ludovic Brenta.

Georg Bauhaus

unread,
Feb 8, 2011, 5:03:44 AM2/8/11
to
On 2/8/11 10:58 AM, Ludovic Brenta wrote:

>> (c) by single case logic, Ada's type system has not prevented
>> deaths in Ariane 5 anyway.
>
> Huh?

You don't even know this?

Ludovic Brenta

unread,
Feb 8, 2011, 5:08:34 AM2/8/11
to
Georg Bauhaus wrote on comp.lang.ada:

The problem was the conscious decision not to re-test the Ariane 4
software against Ariane 5 due to the incorrect assumption that the
accelerations involved had not changed. It had everything to do with
management and nothing with software engineering (in fact the software
engineers were denied the right to test the software against "secret"
Ariane 5 predicted trajectory data).

There were no deaths involved.

So: huh?

--
Ludovic Brenta.

Georg Bauhaus

unread,
Feb 8, 2011, 5:10:37 AM2/8/11
to
On 2/8/11 9:04 AM, Ludovic Brenta wrote:
> The thing you
> implemented "easily" had a bug.

No. Stupid programmers can easily misuse foo() just as
Ada programmers can easily write violations of index
constraints. Hopefully, they write exception handlers.
But wait. If the handlers are just as smart as their
use of indexing variables... Isn't their ambition flawed
by a logical contradiction? If the handlers are just
as good as the checked indexing...

Georg Bauhaus

unread,
Feb 8, 2011, 5:11:29 AM2/8/11
to
On 2/8/11 9:04 AM, Ludovic Brenta wrote:

> BTW, like I said, *every* time I look at C code, I see a bug. In your
> case, foo has undefined behavior if countdown is negative.

You took the bait. Fine.

Strict contracts in subprogram profiles. Ha!

void foo2(int jump)
/* make sure jump % 2 == 0! */
{
...
}

Write that in Ada 2005 to demonstrate the glorious power of
your subtype constraints. When was it that compilers will
support aspects reliably?

Ludovic Brenta

unread,
Feb 8, 2011, 5:14:08 AM2/8/11
to

No. Stupid programmers use "int" when they really mean "positive", and
they don't even explain that to users of their APIs. Not even in
comments. Then they say bugs are every one else's fault but theirs.

--
Ludovic Brenta.

Nasser M. Abbasi

unread,
Feb 8, 2011, 5:15:09 AM2/8/11
to
On Feb 8, 2:03 am, Georg Bauhaus <rm-host.bauh...@maps.futureapps.de>
wrote:

Hello;

From wiki:

http://en.wikipedia.org/wiki/Ariane_5_Flight_501

"Because of the different flight path, a data conversion from a 64-bit
floating point to 16-bit signed integer value caused a hardware
exception (more specifically, an arithmetic overflow, as the floating
point number had a value too large to be represented by a 16-bit
signed integer). Efficiency considerations had led to the disabling of
the software handler (in Ada code) for this error trap"

So, the problem was "disabling of the software handler".

So, it seems to me that Ada worked as expected? It DID detect the
overflow.

But someone has disabled run-time exception handler.

--Nasser

Ludovic Brenta

unread,
Feb 8, 2011, 5:16:44 AM2/8/11
to
Georg Bauhaus wrote on comp.lang.ada:

Easy:

procedure Foo2 (Jump : in Natural);
-- Jumps by 2 * Jump

Thereby eliminating the very *possibility* that 2*jump can be odd!

--
Ludovic Brenta.

Georg Bauhaus

unread,
Feb 8, 2011, 5:27:53 AM2/8/11
to
On 2/8/11 11:08 AM, Ludovic Brenta wrote:
> Georg Bauhaus wrote on comp.lang.ada:
>> On 2/8/11 10:58 AM, Ludovic Brenta wrote:
>>>> (c) by single case logic, Ada's type system has not prevented
>>>> deaths in Ariane 5 anyway.
>>
>>> Huh?
>>
>> You don't even know this?
>
> The problem was the conscious decision not to re-test the Ariane 4
> software against Ariane 5 ....

>
> There were no deaths involved.
>
> So: huh?

See? You talk about C functions as if there was a general
case: C functions, plural. Recurring bugs in them, causing
undefined behavior. I made up the same thing for rocket flights
in general. The generalizing argument is structurally equivalent!
Both arguments are pointless because people won't listen.
(Watch Sarah P. to see why arguing about foo(int undefined) is
pointless.)

There is a chance of human error (in C, in rockets).
Smart engineers don't make them (in C, in rockets).
C or Ada have had little to do with these human
errors cause by the wrong assumptions
(about foo() and about Ariane 4 modules).

Here it is, again, my foo() vs Ariane 4/5:

Construction made by a human, in C,
knowing how it was going to be used.

Construction made by a human, in Ada,
knowing how it was going to be used.

In general, where is the difference?

Georg Bauhaus

unread,
Feb 8, 2011, 5:31:08 AM2/8/11
to
On 2/8/11 11:14 AM, Ludovic Brenta wrote:
> Then they say bugs are every one else's fault but theirs.

Exactly!

And they are right because it *is* everyone else fault
if they call a function they don't understand!
Because their programs do demonstrably work, and they
do so *because* they call their own functions as they
should be called.

Obviously.

Georg Bauhaus

unread,
Feb 8, 2011, 5:36:12 AM2/8/11
to
On 2/8/11 11:16 AM, Ludovic Brenta wrote:

>> Strict contracts in subprogram profiles. Ha!
>>
>> void foo2(int jump)
>> /* make sure jump % 2 == 0! */
>> {
>> ...
>>
>> }
>>
>> Write that in Ada 2005 to demonstrate the glorious power of
>> your subtype constraints. When was it that compilers will
>> support aspects reliably?
>
> Easy:
>
> procedure Foo2 (Jump : in Natural);
> -- Jumps by 2 * Jump
>
> Thereby eliminating the very *possibility* that 2*jump can be odd!

See how you couldn't provide a solution, but made up
a different case? Now

Foo2 (Jump => Natural'Last);

Ludovic Brenta

unread,
Feb 8, 2011, 5:43:56 AM2/8/11
to
Georg Bauhaus wrote on comp.lang.ada:

No, I provided a proper contract that reflects the problem at hand
rather than your fragile solution.

  Now
>
>    Foo2 (Jump => Natural'Last);

procedure Foo2 (Jump : in Natural) is
begin
if Jump <= Natural'Last / 2 then
Baz (2 * Jump);
else
declare
Half_Jump : constant Natural := Jump / 2;
Remainder : constant Natural := Jump mod 2;
begin
Baz (2 * Half_Hump);
Baz (2 * Half_Jump);
if Remainder /= 0 then
Baz (2 * Remainder);
end if;
end;
end if;
end Foo2;

And that's assuming Long_Long_Integer is not wide enough for the
calculations.

--
Ludovic Brenta.

Georg Bauhaus

unread,
Feb 8, 2011, 7:20:25 AM2/8/11
to
On 08.02.11 11:43, Ludovic Brenta wrote:
> Georg Bauhaus wrote on comp.lang.ada:
>> On 2/8/11 11:16 AM, Ludovic Brenta wrote:
>>>> Strict contracts in subprogram profiles. Ha!
>>
>>>> void foo2(int jump)
>>>> /* make sure jump % 2 == 0! */
>>>> {
>>>> ...
>>>> }

> procedure Foo2 (Jump : in Natural) is


> begin
> if Jump <= Natural'Last / 2 then
> Baz (2 * Jump);
> else
> declare
> Half_Jump : constant Natural := Jump / 2;
> Remainder : constant Natural := Jump mod 2;
> begin
> Baz (2 * Half_Hump);
> Baz (2 * Half_Jump);
> if Remainder /= 0 then
> Baz (2 * Remainder);
> end if;
> end;
> end if;
> end Foo2;
>
> And that's assuming Long_Long_Integer is not wide enough for the
> calculations.


There is lots of assuming here. The original "contract" read

void foo2(int jump)
/* make sure jump % 2 == 0! */
{
...
}

(And int includes negative values.) The idea could have
been that the least significant bit is not set. Or the idea
could have been different. The point is, neither language
provides the means of expressing the idea using types.

Not yet.

The knee jerk reaction of the Ada programmer is to invent
a different problem and its solution and show off.

It's counterproductive.

So, more specifically, define an integer subtype T whose values
do not include the values of the static constants A, B, and C,
assuming that each of A, B, and C will be members of a
proper subrange of T'Range. Make sure that membership in T
can be checked at compile time.

Do the same for run-time values A, B, and C.

What I'd like to point out is that we need a better utility
function. A function that properly measures program quality.
I imagine that type checking quality vs the type system's
flexibility of the respective languages form one variable
of the utility function.

Simon Clubley

unread,
Feb 8, 2011, 7:46:41 AM2/8/11
to
On 2011-02-07, Randy Brukardt <ra...@rrsoftware.com> wrote:
> "Simon Clubley" <clubley@remove_me.eisner.decus.org-Earth.UFP> wrote in
> message news:iiopbr$bs7$1...@news.eternal-september.org...
>
> You mean a numeric literal (to use the Ada terms).
>

Yes. I was in too much of a rush when I wrote the original posting.

>> In the statement:
>>
>> c = (4 * i) + 2
>>
>> the compiler would allocate memory locations containing the values 4 and
>> 2.
>> These memory locations would then be used in the generated code whenever
>> the
>> values of 2 or 4 were found. In other words, all access, including
>> literals,
>> was by reference.
>>
>> This was a long time ago however.
>
> Must have been. I remember hearing this story in college. And it supposely
> was old then. I've always thought of it as a sort of urban legend. But I
> suspect that it has more to do with the instruction set of the target
> machine. On the Intel architectures that I've worked on my entire working
> life, it wouldn't make sense to have a global memory location holding a
> literal (the literals can be folded into instructions at very little cost).
> But I can imagine cases where that wouldn't be true.
>

As someone else has commented in another posting, something like this also
happened to them, but I can see how it might be considered a urban legend if
you have only used more mainstream hardware.

In my case, this was during the 1980's while I was still in the sixth form
(the US equivalent of the sixth form would be high school) and was taking
advanced (for the time :-)) programming classes at the local higher education
establishment as part of my sixth form education.

The miniframe which was installed there was a obscure miniframe from
Sperry/Unisys and not something mainstream like a PDP-11. The operating
system and compilers were quite limited even by the standards of what was
available in those days and given these other limitations, this global
sharing and allowed overwriting of literals by the generated compiler
code is not a surprise in hindsight.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world

J-P. Rosen

unread,
Feb 8, 2011, 8:12:25 AM2/8/11
to
Le 07/02/2011 22:54, Randy Brukardt a écrit :
> Must have been. I remember hearing this story in college. And it supposely
> was old then. I've always thought of it as a sort of urban legend.
It is not. I was also bitten by this one when I was a student.

The key is that FORTRAN IV required all parameter passing to be by
reference. In a call like:
CALL SP (4)
how do you pass "4" by reference? You have to create a variable. The
compiler was clever enough to create only one variable for each static
value. But inside SP, nothing prevented you from modifying the formal...

Fortunately, our machine had memory protection, and the compiler
generated those pseudo-variables in read-only memory. So you had a
memory access violation, which was easier to debug than when all 4's
were changed to 5's


--
---------------------------------------------------------
J-P. Rosen (ro...@adalog.fr)
Adalog a déménagé / Adalog has moved:
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00

Yannick Duchêne (Hibou57)

unread,
Feb 8, 2011, 8:34:23 AM2/8/11
to
Le Thu, 03 Feb 2011 09:00:24 +0100, Georg Bauhaus
<rm-host...@maps.futureapps.de> a écrit:
> The Ada archives should, I think, have examples of writing to
> DOS's video buffer.
Tiny note aside: B800:0000 or B8000 (as linear address), was not the DOS
video buffer, this was the place where the VGA RAM was mapped to. If I am
not wrong, this was not a DOS matter, but a VGA matter (may be depending
on how the BIOS was setting up the adapter also).

--
Si les chats miaulent et font autant de vocalises bizarres, c’est pas pour
les chiens.

“I am fluent in ASCII” [Warren 2010]

Yannick Duchêne (Hibou57)

unread,
Feb 8, 2011, 8:43:22 AM2/8/11
to
Le Thu, 03 Feb 2011 09:08:50 +0100, mockturtle <frame...@gmail.com> a
écrit:

>> Below is an
>> example of code I would like to be able to implement.
>>
>> ...
>> unsigned int print(char *message, unsigned int line)
>> {
>> char *vidmem = (char *) 0xb8000;
>> unsigned int i= 0;
>>
>
> I do not have any experience about this part of Ada, but maybe I can
> give you a "pointer" to some bootstrapping information. Maybe you could
> want to use an attribute representation clause for Vidmem'Address (see
> Section 13.3 of the RM) . With some improvisation, I would write
> something like
>
> type Vidmem_Array is array (natural range <>) of Character;
> Vidmem : Vidmem_Array (0 .. Max_Size);
>
> for Vidmem'Address use 16#000B_8000#;

There may be a real issue here. This was segment register = B800 and
offset register = 0000, for the base address. Ada does not make any
distinction about segment and offset. There should be something stated in
the compiler's documentation, to know how it maps linear address to
segment:offset address. Otherwise, I feel the result is unpredictable
because ambiguous: the compiler may have at least two options. The first
one would be to work with a fixed segment as the base address for each
memory pool and then the address attribute would match the offset only
(Pascal compilers was working this way inside of units). The second one
would be to use the standard convention at that time, to have offset range
in 0..15 and the remaining of the address held by the segment… the was the
Borland C++ way when using the so called Huge Memory model. These two
interpretation ends into different things. In short, there is no way to
believe “for Vidmem'Address use 16#000B_8000#” can be OK without further
investigations.

Hyman Rosen

unread,
Feb 8, 2011, 10:36:23 AM2/8/11
to
On 2/7/2011 4:00 AM, Ludovic Brenta wrote:
> I recently found another bug in a C program that was caused
> by changing the value of a "passed-by-copy" parameter. Of
> course the caller was unaffected but the algorithm inside
> the function was broken.

In C or C++, a function parameter is an ordinary variable
which is initialized by the an expression in the function
call. If the parameter is not const, it may then be changed
during the operation of the function. C has worked this way
for something like forty years, so being surprised by this
now seems disingenuous.

There's no particular reason that a function parameter should
not be permitted to be changed, notwithstanding that you found
a case where doing so caused an error. One puts implementation,
for example, is

int puts(char *s)
{
while (*s) if (putchar(*s++) == EOF) return EOF;
return putchar('\n');
}

and a C programmer would be puzzled when told that this function
would be better if he had to use another variable initialized to
the value of 's' before getting down to business.

I rather think that it's Ada that got it wrong here, by choosing
to combine the concept of passing by value or reference and the
concept of immutability. Evidence for that is the fact that in
several places the Ada standard has to say that a parameter must
be passed by reference while the declaration of the subprogram
does not give you that information (because the parameter is 'in').

Adam Beneschan

unread,
Feb 8, 2011, 11:44:40 AM2/8/11
to
On Feb 8, 7:36 am, Hyman Rosen <hyro...@mail.com> wrote:
> On 2/7/2011 4:00 AM, Ludovic Brenta wrote:> I recently found another bug in a C program that was caused
> > by changing the value of a "passed-by-copy" parameter. Of
>
>  > course the caller was unaffected but the algorithm inside
>  > the function was broken.
>
> In C or C++, a function parameter is an ordinary variable
> which is initialized by the an expression in the function
> call. If the parameter is not const, it may then be changed
> during the operation of the function. C has worked this way
> for something like forty years, so being surprised by this
> now seems disingenuous.
>
> There's no particular reason that a function parameter should
> not be permitted to be changed, notwithstanding that you found
> a case where doing so caused an error. One puts implementation,
> for example, is
>
>      int puts(char *s)
>      {
>          while (*s) if (putchar(*s++) == EOF) return EOF;
>          return putchar('\n');
>      }

But if C has been working this way for forty years, and its
programmers still can't get it right (as evidenced by the fact that
Ludovic found a bug), then it's arguable that the language is making
it too easy to write incorrect code and too difficult to write code
you can count on. A two-line example such as yours doesn't count as
evidence against that; it's easy to get really short subroutines
correct. The problems come up when you have larger routines. And
I've run into this problem with a program I maintain, in a language
(not C) that also allows value parameters to be modified locally.
Someone has gone into it and written a statement that uses the
parameter, assuming that it's the value that the caller gave it,
without realizing that someone else had written a statement up above
that changed the parameter's value.

There's always going to be a religious war between those who want a
language that doesn't make them do extra annoying stuff and putting
annoying restrictions on their code, and those who prefer a language
that provides some degree of protection against stupid errors (not
only their own, but stupid errors made by the other programmer down
the hall who got laid off two years ago). I'm certainly not going to
resolve the religious war here. But since I do so much of my work
with other people's code, I do have a preference for the latter, and I
think Ada got this one right.

-- Adam

Adam Beneschan

unread,
Feb 8, 2011, 11:48:11 AM2/8/11
to
On Feb 8, 2:03 am, Georg Bauhaus <rm-host.bauh...@maps.futureapps.de>
wrote:

Quoting Wikipedia: "As it was an unmanned flight, there were no
victims". What "deaths" are you referring to? I think that's what
Ludovic meant by "Huh?".

-- Adam

Pascal Obry

unread,
Feb 8, 2011, 12:11:24 PM2/8/11
to Georg Bauhaus
Le 08/02/2011 10:46, Georg Bauhaus a �crit :

> As Hyman said, there are tons of well working C programs out there,
> very likely using some int i, plus increment or decrement.

Sure, I agree 100% with you. The question what was the cost to have the
code running fine? We can also see many assembly code running fine, what
what the cost per line?

I'm not a guy having fun playing with a language that want to kill me or
empty my pocket because I need to spend energy on intrinsic problems. I
want to concentrate to my application domain not to C/C++ idiosyncrasy!

So for what it's worth I agree 100% with Ludovic. I too see bugs in
every C line of code...

Pascal.

--

--|------------------------------------------------------
--| Pascal Obry Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--| http://www.obry.net - http://v2p.fr.eu.org
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver keys.gnupg.net --recv-key F949BD3B

Pascal Obry

unread,
Feb 8, 2011, 12:11:39 PM2/8/11
to Georg Bauhaus
Le 08/02/2011 10:46, Georg Bauhaus a �crit :
> As Hyman said, there are tons of well working C programs out there,
> very likely using some int i, plus increment or decrement.

Sure, I agree 100% with you. The question what was the cost to have the

Pascal Obry

unread,
Feb 8, 2011, 12:11:50 PM2/8/11
to
Le 08/02/2011 10:46, Georg Bauhaus a �crit :
> As Hyman said, there are tons of well working C programs out there,
> very likely using some int i, plus increment or decrement.

Sure, I agree 100% with you. The question what was the cost to have the

Hyman Rosen

unread,
Feb 8, 2011, 12:13:55 PM2/8/11
to
On 2/8/2011 11:44 AM, Adam Beneschan wrote:
> But if C has been working this way for forty years, and its
> programmers still can't get it right (as evidenced by the fact that
> Ludovic found a bug), then it's arguable that the language is making
> it too easy to write incorrect code and too difficult to write code
> you can count on. A two-line example such as yours doesn't count as
> evidence against that; it's easy to get really short subroutines
> correct. The problems come up when you have larger routines. And
> I've run into this problem with a program I maintain, in a language
> (not C) that also allows value parameters to be modified locally.
> Someone has gone into it and written a statement that uses the
> parameter, assuming that it's the value that the caller gave it,
> without realizing that someone else had written a statement up above
> that changed the parameter's value.

An anecdotal reference, and not even showing the problematic code,
does not constitute compelling evidence. I don't see why the same
error might not arise with respect to any variable that a programmer
assumes has one value while in fact it has been changed to another.

> A two-line example such as yours doesn't count as
> evidence against that; it's easy to get really short subroutines
> correct. The problems come up when you have larger routines.

Then don't write large routines. In fact, you should switch to my
new imaginary programming language Lydia. In that language, all
subprograms can be no longer than five lines, since made-up statistics
show that 95% of all programming errors occur in subprograms which are
longer.

Hyman Rosen

unread,
Feb 8, 2011, 12:24:17 PM2/8/11
to
On 2/8/2011 12:11 PM, Pascal Obry wrote:
> I want to concentrate to my application domain not
> to C/C++ idiosyncrasy!

You mean like Ada, where you have to know the difference
between bounded and unbounded strings before you can just
go ahead and focus on your domain?

> So for what it's worth I agree 100% with Ludovic.
> I too see bugs in every C line of code...

Perhaps that makes you unsuited to look at C code?

C has been in continuous use for around forty years,
and there are enormous amounts of working C code
everywhere. If you believe that every line of C code
is broken, I submit that the fault lies in you, not
in the code - you may not understand how to evaluate
C code properly.

Jeffrey Carter

unread,
Feb 8, 2011, 1:03:11 PM2/8/11
to
On 02/08/2011 06:12 AM, J-P. Rosen wrote:
>
> The key is that FORTRAN IV required all parameter passing to be by
> reference. In a call like:
> CALL SP (4)
> how do you pass "4" by reference? You have to create a variable. The
> compiler was clever enough to create only one variable for each static
> value. But inside SP, nothing prevented you from modifying the formal...

The story I heard about the FORTRAN-IV compiler on the CDC 6400 I learned on in
1975 was that certain "common" values (0, 1, 2, ...) were stored in global
memory locations, used by all programs. So if one program changed the value of
"2", every other program would get the wrong value thereafter until the system
was restarted.

I never tested it, and never heard of it happening, so I can't say if it was true.

--
Jeff Carter
"Mr. President, we must not allow a mine-shaft gap!"
Dr. Strangelove
33

Dmitry A. Kazakov

unread,
Feb 8, 2011, 1:14:00 PM2/8/11
to
On Mon, 7 Feb 2011 15:11:23 -0800 (PST), Maciej Sobczak wrote:

> On Feb 7, 10:24�am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>
>>> The contract is not broken. The function cannot modify the original
>>> value that is passed by copy (this being the very nature of "copy")
>>> and the caller cannot even reason about what happens behind the
>>> signature.
>>
>> It is broken because const T is not substitutable for T. Mutators of the
>> type T are not operations of const T. q.e.d.
>
> q.e.d. what?

1. const T /= T
2. not (const T <: T)

> I have an impression that we are (again) in the mode where you bring
> arbitrarily twisted definitions in order to prove your point.
>
> What contract is broken?
>
> Why do you want to substitute one type by another?

Because one is passed as a parameter where another is declared, expected
and used. This is substitution.

> These are not
> generics, nor other type-dependent constructs, so type substitutions
> are out of the picture.

Not at all. const T and T are distinct [sub]types. The types are different
because the sets of operations defined on them are.

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

Georg Bauhaus

unread,
Feb 8, 2011, 1:25:19 PM2/8/11
to

The C programmers vs the Ada programmers kind of deaths
that inevitably happen in those rocket functions that,
by the laws of the wrong language, have shown that failure
must ensue because we have seen it once. -- You know, they
did use Ada in that rocket and it exploded! said some authority
and therefore, by Palinian logic, anything other than Ada is
better and rockets should not explode above the heads of American
people. That's not what we pay our taxes for, for funding
a government compiler that makes rockets explode. -- But it
was a different rocket. -- Well, I think that if it happened
in another rocket, we should be happy that not both of
them have made people die. -- They didn't use GNAT either. --
So you are saying that GNAT is not an Ada compiler? They were
so proud to use Ada and then the rocket exploded. -- But
no one died in Ariane 5. It was unstaffed. -- I think you
are dishonest to the American people. They've got a right to
learn that using "in" mode parameters in preference over
passing copies can kill our astronauts. -- Ariane 5 is a
European rocket. -- It lifts off in French Guiana.
That's very close to Florida, isn't it? --

This kind of death. Of argument. The birth of rhetoric.
Things are made up for the sake of argument. Which is why
I mixed several perfectly comparable rockets: they all
look the same, as we all can see. Too much of this
happens in language comparisons.

It is very good to learn about traceable cases of the danger
inherent in some language, such as using mutable scalars
from the largest possible scope they can have inside
functions (parameters in C; better in Ada?).

I wish they were collected in some unbiased public wiki,
together with a kind of cost analysis, metaphorical or real,
of the observed effects. Wouldn't this be a nice addition
to the Style Guide? A chapter on Bug Avoidance Techniques (BAT)?.

I bet Les Hatton would find this chapter to be in line with his
evaluation of style guides.

Dmitry A. Kazakov

unread,
Feb 8, 2011, 1:27:55 PM2/8/11
to
On Tue, 08 Feb 2011 12:24:17 -0500, Hyman Rosen wrote:

> C has been in continuous use for around forty years,
> and there are enormous amounts of working C code
> everywhere.

Slavery was around for thousands of years. Slaves built the Colosseum and
Pyramids. How silly of us would be not to deploy such an established
economical and technological framework.

> If you believe that every line of C code
> is broken, I submit that the fault lies in you, not
> in the code - you may not understand how to evaluate
> C code properly.

Yes, there is something wrong with us...

Remember the episode in Space Quest III with slave programmers working at
ScumSoft company? I bet they used C. (:-))

Jeffrey Carter

unread,
Feb 8, 2011, 1:30:51 PM2/8/11
to
On 02/08/2011 03:14 AM, Ludovic Brenta wrote:
>
> No. Stupid programmers use "int" when they really mean "positive", and
> they don't even explain that to users of their APIs. Not even in
> comments. Then they say bugs are every one else's fault but theirs.

From the Ada mind-set point of view, this is correct. But in the C mind set,
there are no APIs. Header files are just complications you have to create to
keep the compiler happy; nobody reads them, and they're generally not commented
or formatted nicely. You are expected (and all C coders expect) that before
using a function, you have read and understand its code and know what it will do.

I once worked on an Ada project that had been done by C people. The package
specs were badly formatted collections of declarations with no comments; the
developers viewed them as header files that no one would read. There were
minimal comments in the bodies, and everyone was expected to read the body code
to understand how to use the operations.

The problem with this is it violates Dijkstra's adage that we have small brains
and must do our work with them. Few of us can keep all the code for the entire
project in his head, and there are times when what one remembers is incorrect.
And so, eventually, in any real project, even the best of developers make errors
under such circumstances.

So, when talking to a C coder, "You said int, so negative values should be OK"
isn't considered a valid argument. The response will be that you are supposed to
have read the code and realized what would happen if you called it with a
negative value. If you then go ahead and do so, you get what you asked for.

Georg Bauhaus

unread,
Feb 8, 2011, 1:33:23 PM2/8/11
to
On 08.02.11 18:13, Hyman Rosen wrote:

> Then don't write large routines.

Is there evidence that a mechanism necessary for combining
the smaller routines leads to fewer errors? I'd like to
believe this if its statistically true.

(And put aside worries about impractical overhead that, for
example, objects have in some languages.)

Hyman Rosen

unread,
Feb 8, 2011, 1:39:40 PM2/8/11
to
On 2/8/2011 1:33 PM, Georg Bauhaus wrote:
> On 08.02.11 18:13, Hyman Rosen wrote:
>
>> Then don't write large routines.
>
> Is there evidence that a mechanism necessary for combining
> the smaller routines leads to fewer errors? I'd like to
> believe this if its statistically true.

I was just joking, as the rest of the post should have made clear.

Hyman Rosen

unread,
Feb 8, 2011, 1:43:02 PM2/8/11
to
On 2/8/2011 1:27 PM, Dmitry A. Kazakov wrote:
> Slavery was around for thousands of years. Slaves built the Colosseum and
> Pyramids. How silly of us would be not to deploy such an established
> economical and technological framework.

Slavery is analogous to Ada, whose rigidity forces
everyone into strict, regimented, and gray coding
practices instead of permitting the open delightful
freedom given by C.

Can we stop this stupidity now?

Hyman Rosen

unread,
Feb 8, 2011, 1:47:26 PM2/8/11
to
On 2/8/2011 1:30 PM, Jeffrey Carter wrote:
> I once worked on an Ada project that had been done by C people.
> The package specs were badly formatted collections of declarations
> with no comments; the developers viewed them as header files that
> no one would read. There were minimal comments in the bodies, and
> everyone was expected to read the body code to understand how to
> use the operations.

Ah, now I understand. No true Scotsman would write bad Ada!

It is loading more messages.
0 new messages