comp.lang.ada
 help / color / mirror / Atom feed
* Uninitialized Variables
@ 1999-01-25  0:00 Roger Racine
  1999-01-25  0:00 ` robert_dewar
  1999-01-25  0:00 ` Tucker Taft
  0 siblings, 2 replies; 94+ messages in thread
From: Roger Racine @ 1999-01-25  0:00 UTC (permalink / raw)


One of the few areas where Ada programs exhibit non-deterministic behavior 
(i.e. different behavior for different runs) is when variables are not set 
before their use.   

I am curious as to why the language designers did not think this was 
sufficiently common enough of an error to protect against it.  I understand 
that having an initial value takes more memory and more CPU, but so do 
constraint checks.  And there could always have been a pragma to allow 
uninitialized variables (akin to pragma SUPPRESS).

By the way, I would be happy with a mechanism at link time that  only 
complained about (or implicitly created initial values for) data that was 
determined might be used before being set. 

The problem is that different environments exhibit different behavior.  Some 
environments put zeros in all of RAM as part of initialization.  This 
sometimes masks the problem (which is fine if portability is not a concern).  
Some put zeros in all static (non-stack, non-heap) variables.  Some even allow 
the user to specify the value to be put in RAM.  And some do nothing at all.

Does anyone know why there is not at least a required link-time warning 
message for variables possibly used before being set?

Roger Racine




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

* Re: Uninitialized Variables
  1999-01-25  0:00 Uninitialized Variables Roger Racine
@ 1999-01-25  0:00 ` robert_dewar
  1999-01-25  0:00 ` Tucker Taft
  1 sibling, 0 replies; 94+ messages in thread
From: robert_dewar @ 1999-01-25  0:00 UTC (permalink / raw)


In article <rracine.7.000B4B63@draper.com>,
  rracine@draper.com (Roger Racine) wrote:
> One of the few areas where Ada programs exhibit
non-deterministic behavior
> (i.e. different behavior for different runs) is when
variables are not set
> before their use.
>
> I am curious as to why the language designers did not
> think this was sufficiently common enough of an error to
> protect against it.  I understand  that having an initial
> value takes more memory and more CPU, but so do
> constraint checks.

You miss the philosophical and design objections to junk
initial values. These arguments are familiar so I won't
repeat them in detail here!

> And there could always have been a pragma to allow
> uninitialized variables (akin to pragma SUPPRESS).

Ada 95 of course has a pragma, but it has the opposite
sense, you use pragma Normalize_Scalars if you want
initializations. The intention of this pragma is precisely
to avoid non-determinism. Why is it not enough for you?

> Does anyone know why there is not at least a required
> link-time warning message for variables possibly used
> before being set?

First, a full analysis at link time of all possible static
flows through a program would be a very heavy burden to
place on a compiler. It is far out of reach of what could
be done in existing implementation frameworks, and I would
have significant efficiency concerns.

Second, requiring warning messages is a big bogus in
anyway. Such requirements are not testable, and not
well-defined. I think it reasonable to let the marketplace
determine the need for warnings.

It is certainly useful for a compiler to do a reasonable
job of detecting obvious cases (try using -gnatwu with
GNAT 3.11p).

Robert Dewar

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: Uninitialized Variables
  1999-01-25  0:00 Uninitialized Variables Roger Racine
  1999-01-25  0:00 ` robert_dewar
@ 1999-01-25  0:00 ` Tucker Taft
  1 sibling, 0 replies; 94+ messages in thread
From: Tucker Taft @ 1999-01-25  0:00 UTC (permalink / raw)


Roger Racine (rracine@draper.com) wrote:

: One of the few areas where Ada programs exhibit non-deterministic behavior 
: (i.e. different behavior for different runs) is when variables are not set 
: before their use.   

: I am curious as to why the language designers did not think this was 
: sufficiently common enough of an error to protect against it.  

I don't know the Ada 83 history on this.  However, simply default
initializing all scalars to something like zero has its own problems,
because it can make it less clear whether the default value is the
desired initial value, or the programmer forgot to properly set the
value.  Initializing pointers by default to null has somewhat the
same problem, but less so, since any dereference of a null pointer
would be caught, whereas any use of a default scalar value would
probably not be caught.

In any case, Ada 95 does include a pragma "Normalize_Scalars" which 
forces the implementation to initialize all scalars to some unspecified 
value, ideally to a value outside of their declared range.  The goal 
here is to create reproducibility, without allowing the programmer 
to "shirk" their responsibility of initializing the variable properly.

: ... I understand 
: that having an initial value takes more memory and more CPU, but so do 
: constraint checks.  And there could always have been a pragma to allow 
: uninitialized variables (akin to pragma SUPPRESS).

I guess I agree that it is a relatively small price to pay, but it did
not seem like something we could insert during the Ada 9X revision.  We
wanted performance to be compatible with Ada 83 as well!  Certainly
Bob Duff, a member of the Ada 9X design team, would agree with your 
suggestions.  Note that in Ada 95 we did change the use of an uninitialized 
variable into a "bounded error" rather than "erroneous."  Even this change 
drew some protests from implementors because of the potential performance 
effects.

: By the way, I would be happy with a mechanism at link time that  only 
: complained about (or implicitly created initial values for) data that was 
: determined might be used before being set. 

We have recently added to our Ada 95 front end detection of potentially
uninitialized local variables.  Detecting potentially uninitialized 
global variables would require some kind of link-time detection.

: The problem is that different environments exhibit different behavior.  Some 
: environments put zeros in all of RAM as part of initialization.  This 
: sometimes masks the problem (which is fine if portability is not a concern).  
: Some put zeros in all static (non-stack, non-heap) variables.  Some even allow 
: the user to specify the value to be put in RAM.  And some do nothing at all.

: Does anyone know why there is not at least a required link-time warning 
: message for variables possibly used before being set?

Requiring specific warnings is generally treading on thin ice from
a language specification point of view.  Even specifying the form
of error messages is difficult.

This is really more of a quality-of-implementation issue, and not
very easy to legislate via the language standard.

: Roger Racine

--
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Distributed IT Solutions  (www.averstar.com/tools)
AverStar (formerly Intermetrics, Inc.)   Burlington, MA  USA




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

* private types
@ 2006-03-13 19:58 ada_student
  2006-03-13 20:27 ` Mark Lorenzen
  2006-03-14  4:51 ` Jeffrey R. Carter
  0 siblings, 2 replies; 94+ messages in thread
From: ada_student @ 2006-03-13 19:58 UTC (permalink / raw)


Consider the following package declaration,

    package PrivateType is

        type MyInteger is private;

        procedure  Read(O : out myInteger);
        procedure Write(I : in MyInteger);

    private

        type MyInteger is range 1 .. 2**31 - 1;

    end;

    Why does Ada allow MyInteger to be made visible outside the
    scope of PrivateType ? Doesnt it make the code less secure(for
    example,consider an "uninitialized" object of type
    PrivateType.MyInteger).




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

* Re: private types
  2006-03-13 19:58 private types ada_student
@ 2006-03-13 20:27 ` Mark Lorenzen
  2006-03-13 21:05   ` Pascal Obry
  2006-03-13 21:07   ` ada_student
  2006-03-14  4:51 ` Jeffrey R. Carter
  1 sibling, 2 replies; 94+ messages in thread
From: Mark Lorenzen @ 2006-03-13 20:27 UTC (permalink / raw)


ada_student@yahoo.com writes:

> Consider the following package declaration,
> 
>     package PrivateType is
> 
>         type MyInteger is private;
> 
>         procedure  Read(O : out myInteger);
>         procedure Write(I : in MyInteger);
> 
>     private
> 
>         type MyInteger is range 1 .. 2**31 - 1;
> 
>     end;
> 
>     Why does Ada allow MyInteger to be made visible outside the
>     scope of PrivateType ? Doesnt it make the code less secure(for
>     example,consider an "uninitialized" object of type
>     PrivateType.MyInteger).

First of all: If you want to learn about Ada, I can recommend the book
"Programming in Ada 95" by John Barnes.

I think that I understand what you are trying to do... You want to
prevent the user of your package from declaring uninitialised
variables of type PrivateType.MyInteger, right? In this case I would
declare the partial view of the type (the non-private part) to be
indefinite:

        type MyInteger (<>) is private;

And then declare a function to provide an initial value of that type:

        function Nil returns MyInteger;

The user of your package can then only declare a variable of type
PrivateType.MyInteger if she initialises it at the same time:

with PrivateType;

[...]

My_Var : PrivateType.MyInteger := PrivateType.Nil;

Again: A good textbook on the subject will give you a much better
understanding of the language than just trying to find Ada equivalents
of C++ intricacies.

- Mark



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

* Re: private types
  2006-03-13 20:27 ` Mark Lorenzen
@ 2006-03-13 21:05   ` Pascal Obry
  2006-03-13 21:07   ` ada_student
  1 sibling, 0 replies; 94+ messages in thread
From: Pascal Obry @ 2006-03-13 21:05 UTC (permalink / raw)
  To: Mark Lorenzen

Mark Lorenzen a �crit :

> I think that I understand what you are trying to do... You want to
> prevent the user of your package from declaring uninitialised
> variables of type PrivateType.MyInteger, right? In this case I would
> declare the partial view of the type (the non-private part) to be
> indefinite:
> 
>         type MyInteger (<>) is private;

Or:

private
   type T is range 1 .. 2**31 - 1;

   type MyInteger is record
      Value : T := 0;
   end record;

This depends on the "real" program. Hard to tell if this is not overkill
for the simple code snippet posted :)

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|              http://www.obry.net
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



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

* Re: private types
  2006-03-13 20:27 ` Mark Lorenzen
  2006-03-13 21:05   ` Pascal Obry
@ 2006-03-13 21:07   ` ada_student
  2006-03-13 21:45     ` Simon Wright
  1 sibling, 1 reply; 94+ messages in thread
From: ada_student @ 2006-03-13 21:07 UTC (permalink / raw)


>
>         type MyInteger (<>) is private;
>

Funny, how my copy of the AARM doesnt include this
construct in the grammar although ObjectAda points
to  LRM:3.3.1(5) which states (in my copy) -->

    "An object_declaration without the reserved word constant
    declares a variable object. If it has a subtype_indication or
    an array_type_definition that defines an indefinite subtype,
    then there shall be an initialization expression. An
    initialization expression shall not be given if the object is
    of a limited type."




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

* Re: private types
  2006-03-13 21:07   ` ada_student
@ 2006-03-13 21:45     ` Simon Wright
  0 siblings, 0 replies; 94+ messages in thread
From: Simon Wright @ 2006-03-13 21:45 UTC (permalink / raw)


ada_student@yahoo.com writes:

>>
>>         type MyInteger (<>) is private;
>>

unknown_discriminant_part .. 3.7(3).

This use is 7.3(11).



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

* Re: private types
  2006-03-13 19:58 private types ada_student
  2006-03-13 20:27 ` Mark Lorenzen
@ 2006-03-14  4:51 ` Jeffrey R. Carter
  2006-03-14  7:44   ` Brian May
  1 sibling, 1 reply; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-14  4:51 UTC (permalink / raw)


ada_student@yahoo.com wrote:

> Consider the following package declaration,
> 
>     package PrivateType is
> 
>         type MyInteger is private;
> 
>         procedure  Read(O : out myInteger);
>         procedure Write(I : in MyInteger);
> 
>     private
> 
>         type MyInteger is range 1 .. 2**31 - 1;
> 
>     end;
> 
>     Why does Ada allow MyInteger to be made visible outside the
>     scope of PrivateType ? Doesnt it make the code less secure(for
>     example,consider an "uninitialized" object of type
>     PrivateType.MyInteger).

Because that's what private means in Ada.

I suggest you spend some time with an Ada text or tutorial. It appears that 
you're guessing at Ada based on experience with another language.

On-line texts and tutorials are available at adapower.com and adaworld.com. If 
you're fairly experienced in another language, you might want to look at "Ada 
Distilled". It's fairly concise while still providing a good introduction to Ada 
concepts.

-- 
Jeff Carter
"You've got the brain of a four-year-old boy,
and I bet he was glad to get rid of it."
Horse Feathers
47



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

* Re: private types
  2006-03-14  4:51 ` Jeffrey R. Carter
@ 2006-03-14  7:44   ` Brian May
  2006-03-14  8:25     ` Ludovic Brenta
                       ` (2 more replies)
  0 siblings, 3 replies; 94+ messages in thread
From: Brian May @ 2006-03-14  7:44 UTC (permalink / raw)


>>>>> "Jeffrey" == Jeffrey R Carter <spam.not.jrcarter@acm.not.spam.org> writes:
    >> MyInteger to be made visible outside the scope of PrivateType ?
    >> Doesnt it make the code less secure(for example,consider an
    >> "uninitialized" object of type PrivateType.MyInteger).

    Jeffrey> Because that's what private means in Ada.

He does have a point though - some languages will initialise all
variables to dummy values - this means you can get predictable results
in code that (wrongly) uses them before setting them to a value.

In this case it is possible to force initialisation (at least outside
the package), as per another poster's suggestion, because it is a
private type. Alternatively it is possible to turn it into a record
type and provide a default value for the component, as per another
post.

In other cases it isn't so easy, e.g. any non-private non-record type.

In fact, by default (at least last time I checked), gcc (or was that
gnat) doesn't check the validity of parameters to functions if the
type matches, even though the type hasn't been initialised and may
just happen to contain an illegal value.

I seem to recall Ada will initialise access types to null, and record
components (if defaults given), but nothing else.
-- 
Brian May <bam@snoopy.apana.org.au>



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

* Re: private types
  2006-03-14  7:44   ` Brian May
@ 2006-03-14  8:25     ` Ludovic Brenta
  2006-03-14  8:47     ` Alex R. Mosteo
  2006-03-17  4:33     ` Justin Gombos
  2 siblings, 0 replies; 94+ messages in thread
From: Ludovic Brenta @ 2006-03-14  8:25 UTC (permalink / raw)


Brian May a écrit :
> In fact, by default (at least last time I checked), gcc (or was that
> gnat) doesn't check the validity of parameters to functions if the
> type matches, even though the type hasn't been initialised and may
> just happen to contain an illegal value.

That is true, you need to pass -gnatVi -gnatVm to enable these checks.

-- 
Ludovic Brenta.




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

* Re: private types
  2006-03-14  7:44   ` Brian May
  2006-03-14  8:25     ` Ludovic Brenta
@ 2006-03-14  8:47     ` Alex R. Mosteo
  2006-03-17  4:33     ` Justin Gombos
  2 siblings, 0 replies; 94+ messages in thread
From: Alex R. Mosteo @ 2006-03-14  8:47 UTC (permalink / raw)


Brian May wrote:
>>>>>>"Jeffrey" == Jeffrey R Carter <spam.not.jrcarter@acm.not.spam.org> writes:
> 
>     >> MyInteger to be made visible outside the scope of PrivateType ?
>     >> Doesnt it make the code less secure(for example,consider an
>     >> "uninitialized" object of type PrivateType.MyInteger).
> 
>     Jeffrey> Because that's what private means in Ada.
> 
> He does have a point though - some languages will initialise all
> variables to dummy values - this means you can get predictable results
> in code that (wrongly) uses them before setting them to a value.
> 
> In this case it is possible to force initialisation (at least outside
> the package), as per another poster's suggestion, because it is a
> private type. Alternatively it is possible to turn it into a record
> type and provide a default value for the component, as per another
> post.
> 
> In other cases it isn't so easy, e.g. any non-private non-record type.
> 
> In fact, by default (at least last time I checked), gcc (or was that
> gnat) doesn't check the validity of parameters to functions if the
> type matches, even though the type hasn't been initialised and may
> just happen to contain an illegal value.
> 
> I seem to recall Ada will initialise access types to null, and record
> components (if defaults given), but nothing else.

Access variables are initialized to null by language definition. 
Normalize_Scalars pragma exists also, and Gnat has Initialize_Scalars I 
think. These can give more control, but IMHO that's an after-the-bug 
resort.



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

* Re: private types
  2006-03-14  7:44   ` Brian May
  2006-03-14  8:25     ` Ludovic Brenta
  2006-03-14  8:47     ` Alex R. Mosteo
@ 2006-03-17  4:33     ` Justin Gombos
  2006-03-17  5:17       ` Brian May
                         ` (2 more replies)
  2 siblings, 3 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-17  4:33 UTC (permalink / raw)


On 2006-03-14, Brian May <bam@snoopy.apana.org.au> wrote:
>
> He does have a point though - some languages will initialise all
> variables to dummy values - this means you can get predictable
> results in code that (wrongly) uses them before setting them to a
> value.

Beyond access types, I would not consider that feature you're
describing helpful.  In fact, it's more of a disservice.  

The first problem: initializing to zero, or some other "dummy" value
of the compilers choice is likely to result in a valid value
(sometimes), which only serves to /hide/ bugs in the cases where the
object is used prior to a meaningful assignment.

Then problem with user forced initialization (which is what the OP is
after): it could mask the cases where reassignment is inevitable.
IOW, suppose you have subprograms like this:

  function exists return boolean is

    --Later assignment to found_it is evitable
    --
    found_it : boolean := false;

  begin

    if some_precondition then

      found_it := some_other_condition;

    end if;

    return found_it;

  end exists;

In the above case, an initial value may persist if some path is not
executed.  The maintainer can immediately expect this to be the case
upon seeing the initialization (assuming the author was competent).
In other cases, an initial value may get overwritten no matter what.
In these cases it makes more sense not to initialize, because it
clarifies to the maintainer what kind of logic to expect before even
looking at the body of code.

It's always irritating to be reading someone elses code, and find that
they've blanket initialized objects needlessly.  It hides bugs, and
also obscures the logic from the maintainer.

We don't know enough about the OPs case to know whether forced
initialization is wise, but he should be cautioned not to take this
approach arbitrarily, or on a regular basis.  It really depends on the
situation.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-17  4:33     ` Justin Gombos
@ 2006-03-17  5:17       ` Brian May
  2006-03-17 22:50         ` Justin Gombos
  2006-03-18  1:17         ` Randy Brukardt
  2006-03-17  7:40       ` Maciej Sobczak
  2006-03-17 13:18       ` Robert A Duff
  2 siblings, 2 replies; 94+ messages in thread
From: Brian May @ 2006-03-17  5:17 UTC (permalink / raw)


I am not sure how this:

  function exists return boolean is

    --Later assignment to found_it is evitable
    --
    found_it : boolean := false;

  begin

    if some_precondition then

      found_it := some_other_condition;

    end if;

    return found_it;

  end exists;

Is any better/worse then this:

  function exists return boolean is

    --Later assignment to found_it is evitable
    --
    found_it : boolean;

  begin

    if some_precondition then

      found_it := some_other_condition;

    end if;

    return found_it;

  end exists;

It is possible a smart compiler might trigger a warning in the second
case - but this depends on you noticing the warning and investigating
it. There are cases when the compiler might get confused and produce
false positives or false negatives.

Otherwise, the above problem is a problem that can only be found
either by careful inspection of the code or by proper testing.

For testing the code, as found_it is undefined in the second test, it
is possible it might just fluke the tests you give it and pass
everyone.

The first code is predictable though, and as long as you give it the
same inputs, it will always produce the same outputs, making it easier
(IMHO) to test.
-- 
Brian May <bam@snoopy.apana.org.au>



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

* Re: private types
  2006-03-17  4:33     ` Justin Gombos
  2006-03-17  5:17       ` Brian May
@ 2006-03-17  7:40       ` Maciej Sobczak
  2006-03-17 16:41         ` Frank J. Lhota
  2006-03-17 23:36         ` Justin Gombos
  2006-03-17 13:18       ` Robert A Duff
  2 siblings, 2 replies; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-17  7:40 UTC (permalink / raw)


Justin Gombos wrote:

>>He does have a point though - some languages will initialise all
>>variables to dummy values - this means you can get predictable
>>results in code that (wrongly) uses them before setting them to a
>>value.
> 
> Beyond access types, I would not consider that feature you're
> describing helpful.  In fact, it's more of a disservice.  

So you have the whole pragma as such "disservice":

http://www.adaic.org/standards/95aarm/html/AA-H-1.html


> The first problem: initializing to zero, or some other "dummy" value
> of the compilers choice is likely to result in a valid value
> (sometimes), which only serves to /hide/ bugs in the cases where the
> object is used prior to a meaningful assignment.

Right. Then, why not minimize the scope of the object to the extent when 
it's never even visible before being initialized with the value that is 
meaningful in the given context? It's not always possible, of course, 
but in many (most?) cases programmers tend to put all variables at the 
beginning of some rather coarse-grained scope (for example, beginning of 
the procedure or function), and later wonder what is the "right" initial 
value for them. It's the misplacement of declaration that is a primary 
source of problems and this is what should be actually addressed.

> Then problem with user forced initialization (which is what the OP is
> after): it could mask the cases where reassignment is inevitable.
> IOW, suppose you have subprograms like this:
> 
>   function exists return boolean is
> 
>     --Later assignment to found_it is evitable
>     --
>     found_it : boolean := false;
> 
>   begin
> 
>     if some_precondition then
> 
>       found_it := some_other_condition;
> 
>     end if;
> 
>     return found_it;
> 
>   end exists;

Single entry - single exit syndrome? :)


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: private types
  2006-03-17  4:33     ` Justin Gombos
  2006-03-17  5:17       ` Brian May
  2006-03-17  7:40       ` Maciej Sobczak
@ 2006-03-17 13:18       ` Robert A Duff
  2006-03-17 23:44         ` Justin Gombos
  2 siblings, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-17 13:18 UTC (permalink / raw)


Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

> On 2006-03-14, Brian May <bam@snoopy.apana.org.au> wrote:
> >
> > He does have a point though - some languages will initialise all
> > variables to dummy values - this means you can get predictable
> > results in code that (wrongly) uses them before setting them to a
> > value.
> 
> Beyond access types, I would not consider that feature you're
> describing helpful.

I'm not sure what the right answer is, but surely all the arguments for
and against dummy values apply equally to access types.

- Bob



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

* Re: private types
  2006-03-17  7:40       ` Maciej Sobczak
@ 2006-03-17 16:41         ` Frank J. Lhota
  2006-03-17 23:36         ` Justin Gombos
  1 sibling, 0 replies; 94+ messages in thread
From: Frank J. Lhota @ 2006-03-17 16:41 UTC (permalink / raw)


Maciej Sobczak wrote:
> Justin Gombos wrote:
> 
>> ....
>>
>> Beyond access types, I would not consider that feature you're
>> describing helpful.  In fact, it's more of a disservice.  
> 
> So you have the whole pragma as such "disservice":
> 
> http://www.adaic.org/standards/95aarm/html/AA-H-1.html

Actually, the purpose of the Normalize_Scalars pragma is to eliminate 
any dependency on default initializations. The idea is to fill those 
scalars that are not initialized by the user with some extreme value, 
preferably out of range, so that any use of an uninitialized value can 
be readily detected.

The Normalize_Scalars pragma is the high level version of the "DEAD 
BEEF" option provided by many Unix C compilers / linkers. As you may 
recall, the C standard specifies that any static data not initialized by 
the user is implicitly initialized to 0. With the "DEAD BEEF" option, 
the static data not initialized in the code is filled with the hex bytes 
0xDEADBEEF, which results in outrageous integer / floating point / 
string values. Again, the point of this option is to eliminate 
dependence on implicit initialization.

>> The first problem: initializing to zero, or some other "dummy" value
>> of the compilers choice is likely to result in a valid value
>> (sometimes), which only serves to /hide/ bugs in the cases where the
>> object is used prior to a meaningful assignment.
> 
> Right. Then, why not minimize the scope of the object to the extent when 
> it's never even visible before being initialized with the value that is 
> meaningful in the given context? It's not always possible, of course, 
> but in many (most?) cases programmers tend to put all variables at the 
> beginning of some rather coarse-grained scope (for example, beginning of 
> the procedure or function), and later wonder what is the "right" initial 
> value for them. It's the misplacement of declaration that is a primary 
> source of problems and this is what should be actually addressed.
> 
>> Then problem with user forced initialization (which is what the OP is
>> after): it could mask the cases where reassignment is inevitable.
>> IOW, suppose you have subprograms like this:
>>
>>   function exists return boolean is
>>
>>     --Later assignment to found_it is evitable
>>     --
>>     found_it : boolean := false;
>>
>>   begin
>>
>>     if some_precondition then
>>
>>       found_it := some_other_condition;
>>
>>     end if;
>>
>>     return found_it;
>>
>>   end exists;
> 
> Single entry - single exit syndrome? :)
> 
> 


-- 
"All things extant in this world,
Gods of Heaven, gods of Earth,
Let everything be as it should be;
Thus shall it be!"
- Magical chant from "Magical Shopping Arcade Abenobashi"

"Drizzle, Drazzle, Drozzle, Drome,
Time for the this one to come home!"
- Mr. Lizard from "Tootor Turtle"



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

* Re: private types
  2006-03-17  5:17       ` Brian May
@ 2006-03-17 22:50         ` Justin Gombos
  2006-03-18  1:17         ` Randy Brukardt
  1 sibling, 0 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-17 22:50 UTC (permalink / raw)


On 2006-03-17, Brian May <bam@snoopy.apana.org.au> wrote:
> I am not sure how this:
>
>   function exists return boolean is
>
>     --Later assignment to found_it is evitable
>     --
>     found_it : boolean := false; 
> 
>   begin
>
>     if some_precondition then
>
>       found_it := some_other_condition;
>
>     end if;
>
>     return found_it;
>
>   end exists;
>
> Is any better/worse then this:
>
>   function exists return boolean is
>
>     --Later assignment to found_it is evitable
>     --
>     found_it : boolean;
>
>   begin
>
>     if some_precondition then
>
>       found_it := some_other_condition;
>
>     end if;
>
>     return found_it;
>
>   end exists;

The second case is obviously careless, and as you say, unpredictible.
The first case is a good approach, as is this alternative:

  function exists return boolean is

    --Later assignment to found_it is inevitable
    --
    found_it : boolean;

  begin

    if some_precondition then

      found_it := some_other_condition;
  
    else

      found_it := a_different_condition;

    end if;

    return found_it;

  end exists;
 
My main purpose was to put the spotlight on this foolish practice:

  function exists return boolean is

    --Later assignment to found_it is inevitable
    --
    found_it : boolean := false; --needless and misleading initialization

  begin

    if some_precondition then

      found_it := some_other_condition;
  
    else

      found_it := a_different_condition;

    end if;

    return found_it;

  end exists;

Users of the OPs API might be forced into this scenario if the API is
constructed to force explicit initialization on instantiation.

> It is possible a smart compiler might trigger a warning in the
> second case - but this depends on you noticing the warning and
> investigating it. There are cases when the compiler might get
> confused and produce false positives or false negatives.
>
> Otherwise, the above problem is a problem that can only be found
> either by careful inspection of the code or by proper testing.

Sure there are multiple opportunities to find flaws; but the idea is
to not depend on them more than we have to.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-17  7:40       ` Maciej Sobczak
  2006-03-17 16:41         ` Frank J. Lhota
@ 2006-03-17 23:36         ` Justin Gombos
  2006-03-18  1:32           ` Randy Brukardt
  2006-03-18  9:20           ` private types Dmitry A. Kazakov
  1 sibling, 2 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-17 23:36 UTC (permalink / raw)


On 2006-03-17, Maciej Sobczak <no.spam@no.spam.com> wrote:
>
> So you have the whole pragma as such "disservice":
>
> http://www.adaic.org/standards/95aarm/html/AA-H-1.html

I don't have a problem with implicit initializations when the compiler
can ensure a bad value (or "abnormal object", to use the language of
the ARM).  I was responding to Brian May's comment about compilers
implicitly assigning "dummy values", which did not sound to me like
values that are intelligently selected to be invalid for the type.
I've heard of compilers implicitly initializing to zero, and figured
that was what he might be advocating.

BTW- I sometimes have a use for creating an abnormal object, and find
     Ada lacking in not providing such a mechanism.  I'm sometimes
     forced to either include abnormal values in the set of values
     declared for a type, or to have a seperate flag.  Both of these
     are messy.  Why not have a 'invalid function added to Ada to
     enable simple and explicit initialization of abnormal objects?

> Right. Then, why not minimize the scope of the object to the extent
> when it's never even visible before being initialized with the value
> that is meaningful in the given context? It's not always possible,
> of course, but in many (most?) cases programmers tend to put all
> variables at the beginning of some rather coarse-grained scope (for
> example, beginning of the procedure or function), and later wonder
> what is the "right" initial value for them. It's the misplacement of
> declaration that is a primary source of problems and this is what
> should be actually addressed.

I agree.  Declare blocks can eliminate some of these issues.  I like
the fact that declare blocks enable me to declare more constants than
variables.  But it's not a full solution.  The opposite extreme of
this would be to introduce a declare block at every introduction of a
new object, which can obviously become detrimental to readability.
It's a trade off that requires judgement - judgement that is unequal
among adaists.

> Single entry - single exit syndrome? :)

Yes, I have that syndrome.  I think I acquired it from the Ada Quality
and Style Guide or a coding standard that I followed at one point.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-17 13:18       ` Robert A Duff
@ 2006-03-17 23:44         ` Justin Gombos
  2006-03-18  9:24           ` Dmitry A. Kazakov
  2006-03-18 12:56           ` Robert A Duff
  0 siblings, 2 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-17 23:44 UTC (permalink / raw)


On 2006-03-17, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
> Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:
>
> I'm not sure what the right answer is, but surely all the arguments
> for and against dummy values apply equally to access types.

I don't agree with that.  Null is a standard abnormal object for
access types in all languages, and can never be taken for something
valid.  Null pointers are quickly detected, and easily understood.

But with any other type, null (zero) is most likely a valid value.
This is probably why the ARM states:

      The implicit initial value for an access subtype is the null
      value of the access type.

But makes no such rule for other types.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-17  5:17       ` Brian May
  2006-03-17 22:50         ` Justin Gombos
@ 2006-03-18  1:17         ` Randy Brukardt
  2006-03-18  2:17           ` Justin Gombos
                             ` (3 more replies)
  1 sibling, 4 replies; 94+ messages in thread
From: Randy Brukardt @ 2006-03-18  1:17 UTC (permalink / raw)


"Brian May" <bam@snoopy.apana.org.au> wrote in message
news:sa4hd5x1wgd.fsf@snoopy.microcomaustralia.com.au...
...
> For testing the code, as found_it is undefined in the second test, it
> is possible it might just fluke the tests you give it and pass
> everyone.
>
> The first code is predictable though, and as long as you give it the
> same inputs, it will always produce the same outputs, making it easier
> (IMHO) to test.

It's not just testing. Ada 95 is very clear that an Ada compiler cannot
assume an object is in range unless it can prove it is initialized. Explicit
initialization makes this proof trivial (and leaving it out may make it
impossible to prove.) Thus, given
    A : Positive := 10;
    B : Positive;
the compiler can assume that A is in range, potentially being able to
eliminate checks and speeding up the code. But it cannot assume that B is in
range (unless it can prove that it is initialized further on).

So I recommend initalizing everything (or assigning it immediately after the
begin) that could be significant to performance.

                                     Randy.





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

* Re: private types
  2006-03-17 23:36         ` Justin Gombos
@ 2006-03-18  1:32           ` Randy Brukardt
  2006-03-18  3:21             ` Handling invalid objects Justin Gombos
  2006-03-18  9:20           ` private types Dmitry A. Kazakov
  1 sibling, 1 reply; 94+ messages in thread
From: Randy Brukardt @ 2006-03-18  1:32 UTC (permalink / raw)


"Justin Gombos" <rpbkbq.xax.gld@uluv.kbq> wrote in message
news:FJHSf.1898$TK2.497@trnddc07...
...
> BTW- I sometimes have a use for creating an abnormal object, and find
>      Ada lacking in not providing such a mechanism.  I'm sometimes
>      forced to either include abnormal values in the set of values
>      declared for a type, or to have a seperate flag.  Both of these
>      are messy.  Why not have a 'invalid function added to Ada to
>      enable simple and explicit initialization of abnormal objects?

You're confusing an "invalid" object with an "abnormal" object. Accessing an
abnormal one is erroneous; surely you don't want to intentionally put that
into your programs. (Remember, "erroneous" is Ada-speak for "anything at all
can happen".)

The reason there is no way to construct invalid values is simple: there is
no requirement that an implementation provide any such values. Some types
(like Integer) don't have any invalid values; what would 'Invalid return for
them. (This is the reason that Normalize_Scalars doesn't require
initialization to invalid values.) Moreover, "invalid" only applies to
scalar objects; there is no similar concept for composite types. In any
case, this is a very complex area, and I don't think anyone wants to tread
here.

I'm dubious about your problem anyway; the values you are talking about are
clearly part of the value set of a type. Claiming that they are not and
trying to avoid including them is just confusing. "Null", for instance, is
just another normal value (there are no valid or invalid values for access
types, as they are not scalar) for an access type. Sure, it means "no
object", and that's a bit unusual, but it's clearly an expected value.

                                     Randy.





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

* Re: private types
  2006-03-18  1:17         ` Randy Brukardt
@ 2006-03-18  2:17           ` Justin Gombos
  2006-03-21  0:08             ` Randy Brukardt
  2006-03-18  8:39           ` Uninitialized variables (was: Re: private types) Dirk Craeynest
                             ` (2 subsequent siblings)
  3 siblings, 1 reply; 94+ messages in thread
From: Justin Gombos @ 2006-03-18  2:17 UTC (permalink / raw)


On 2006-03-18, Randy Brukardt <randy@rrsoftware.com> wrote:
>
> Thus, given
>     A : Positive := 10;
>     B : Positive;
> the compiler can assume that A is in range, potentially being able
> to eliminate checks and speeding up the code. But it cannot assume
> that B is in range (unless it can prove that it is initialized
> further on).
>
> So I recommend initalizing everything (or assigning it immediately
> after the begin) that could be significant to performance.

As a rule, I try to put readability ahead of optimizations.  But if I
did want to write optimum code, I'm not seeing your point here.  

The runtime checks that might be placed on B need not affect code not
handling B.  Assuming an extreme case, suppose B is not assigned until
100 lines later (ie not immediately following the begin).  There
should be no runtime checks in those 100 lines between the 'begin' and
the first assignment to B if B is not referenced (and if B is
referenced prior to assignment, that's a problem that outweighs
excessive checks anyway).  The first occurrance of B is going to be an
assignment to B, and it must have the same checks that A would have if
A were being reassigned at this point.  So I'm not seeing why more
runtime checks would occur in the case of B.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Handling invalid objects
  2006-03-18  1:32           ` Randy Brukardt
@ 2006-03-18  3:21             ` Justin Gombos
  2006-03-18  7:35               ` Jeffrey R. Carter
                                 ` (3 more replies)
  0 siblings, 4 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-18  3:21 UTC (permalink / raw)


On 2006-03-18, Randy Brukardt <randy@rrsoftware.com> wrote:
>
> You're confusing an "invalid" object with an "abnormal"
> object. Accessing an abnormal one is erroneous; surely you don't
> want to intentionally put that into your programs. (Remember,
> "erroneous" is Ada-speak for "anything at all can happen".)

The 'Valid attribute exists to be able to handle abnormal objects.

Here's a concrete example.  Suppose I have:

  type clock_type is mod 12;

  function hour_of_day return clock_type;

If hour_of_day gets called and for whatever reason I cannot return an
hour_of_day, the caller needs to know that.  Exceptions are a poor
choice.  The quality and style guide advises against them for a good
reason; exceptions are like gotos - and produce a questionable state.
It would be more graceful for me to return an invalid value (like -1),
so my caller can simply do a 'Valid to discover whether the operation
was successful.

So what are the choices?  

  1) Declare it as:

     type clock_type is mod 13;

     and add special handling code every time you increment or
     decrement the value to what you've chosen to be invalid.

  2) Wrap clock_type in a record, and include a validity flag.  Or
     loosely pass a flag back.  

  3) The hacker approach probably resembles something like this:

     invalid_hour_of_day : constant integer := -1;
     return_data         : clock_type;

     if cannot_get_valid_time then

       for return_data'address use invalid_hour_of_day'address

       return return_data;

     end if;

  4) Raise an exception.

Did I miss any?  They're all pretty sloppy.  The second choice is
probably the best one.  

Approach 2 on steroids: I previously worked on a team that had a
generic package called something like validated_object, where you
would pass in a type and it would return a private type which was
internally a record with a flag and your type.  Then you would call
the provided "valid" function to get the validity status, a set
function to set the status, and you'd have to call another function to
get at the data.  It was kind of a hassle to have to repackage things
whenever handling something that may be invalid.  It nearly doubled
the number of types we handled because every type would have the
validated version, but it was at least a way to pass objects that may
be invalid, and it was used uniformly throughout the project (as
opposed to each developer picking from any of the other approaches).



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

* Re: Handling invalid objects
  2006-03-18  3:21             ` Handling invalid objects Justin Gombos
@ 2006-03-18  7:35               ` Jeffrey R. Carter
  2006-03-18 16:10                 ` Justin Gombos
  2006-03-18  8:57               ` Jacob Sparre Andersen
                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-18  7:35 UTC (permalink / raw)


Justin Gombos wrote:
> 
> The 'Valid attribute exists to be able to handle abnormal objects.

And it exists to handle results from outside normal Ada processing, such as 
values from hardware or from interfacing to other languages.

There's a basic SW-engineering principle that one thing should have one meaning. 
Using one thing with 2 meanings, which is what you're asking for, clearly 
violates that principle.

You'll find plenty of code, including some things in the standard Ada library, 
that violate this principle. Nevertheless, it is rarely a good idea to violate 
this principle.

>   type clock_type is mod 12;
> 
>   function hour_of_day return clock_type;

This seems to specify a function that is expected to always be able to return a 
valid value. If it is expected to only be able to return a valid value some of 
the time, that should be documented, probably by naming the function something 
like Try_To_Get_Hour_Of_Day.

If the function should always be able to return a valid value, and it can't, 
that is clearly an exceptional situation, and an exception is clearly the 
correct way to deal with such a situation.

If valid values are not always possible, then it's a question of how often they 
are not available. If it's a fairly common occurrence (and that can be less than 
50% of the time), then it's not an exceptional situation, and an unconstrained 
record type with a Boolean discriminant is probably the best thing to return. 
If, on the other hand, it's a rare occurrence, then it's still an exceptional 
situation, and an exception is the correct solution.

Anyone who has seen C code that correctly checks and deals with all returned 
error codes and success flags knows how complicated and unreadable such code is. 
The common practice in C is to not do the necessary checks so that the code is 
simpler and more readable. That is clearly not an acceptable solution. 
Exceptions separate the normal processing from the exceptional processing, 
allowing simple and readable code for the normal case while ensuring that all 
checks are performed and dealt with.

There are cases where exceptions are outlawed; most of them are not justified. 
Even if they were all justified, advocating a return to the mess that error 
codes create is not a viable option.

-- 
Jeff Carter
"The time has come to act, and act fast. I'm leaving."
Blazing Saddles
36



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

* Uninitialized variables (was: Re: private types)
  2006-03-18  1:17         ` Randy Brukardt
  2006-03-18  2:17           ` Justin Gombos
@ 2006-03-18  8:39           ` Dirk Craeynest
  2006-03-18 14:06             ` Gautier
                               ` (2 more replies)
  2006-03-18 12:06           ` private types Martin Dowie
  2006-03-18 12:47           ` Robert A Duff
  3 siblings, 3 replies; 94+ messages in thread
From: Dirk Craeynest @ 2006-03-18  8:39 UTC (permalink / raw)


[This thread really is about uninitialized variables now, so I changed
the subject...]

In article <e_mdncFXrsg5wobZnZ2dnUVZ_t2dnZ2d@megapath.net>,
Randy Brukardt <randy@rrsoftware.com> wrote:
>So I recommend initalizing everything (or assigning it immediately
>after the begin) that could be significant to performance.

We did (and do) feel this is not a good approach, at least not when
using GNAT or another compiler that supports something like the pragma
Initialize_Scalars and enhanced validity checking.

For much more about uninitialized variables in Ada code, the following
paper might be useful:

  "Exposing Uninitialized Variables: Strengthening and Extending
  Run-Time Checks in Ada" [1],
  Robert Dewar, Olivier Hainque, Dirk Craeynest, and Philippe
  Waroquiers,
  In "Proceedings of the 7th International Conference on Reliable
  Software Technologies - Ada-Europe 2002" [2], Vienna, Austria,
  June 17-21, 2002, Johan Blieberger and Alfred Strohmeier (Eds.),
  volume 2361 of Lecture Notes in Computer Science, pages 193-204,
  Springer-Verlag, 2002.

The conclusion of that paper contains our recommendation:

---start-quote---

5.3 Impact of Usage of Initialize Scalars on How to Program

There is a trend in programming guidelines to "force" initializing
everything at declaration resulting in code like:

  B : Natural := 0;

  if .... then
    B := 5;
  else
    B := 8;
  end if;

The difficulty with such an approach is that the initial value is
meaningless. If this value is used accidentally, the results are
potentially just as wrong as the use of an uninitialized value, and
furthermore, the explicit initialization precludes the approach we
have described in this paper, and thus may introduce bugs that are much
harder to find and fix. The automatic initialization under control of
the compiler using Initialize Scalars is a far preferable approach.

We therefore recommend that when a scalar is declared, the programmer
should avoid initializing it if the code is supposed to set the value
on all paths.  It is better to let Initialize Scalars + gnatVa detect
the bug in the code logic rather than trying to deal with meaningless
initial values. Even for safety-critical programs, we can first compile
with Initialize Scalars + gnatVa + invalid values and then, if needed,
field the code with Initialize Scalars + all zero values (if it is the
case that zero values give the code a better chance of avoiding
seriously improper behavior).

---end-quote---

The GNAT manuals provide more information on GNAT's pragma
Initialize_Scalars [3] and on enhanced validity checking [4].
Reference [3] mentions:

---start-quote---

Note that pragma Initialize_Scalars is particularly useful in
conjunction with the enhanced validity checking that is now provided
in GNAT, which checks for invalid values under more conditions.
Using this feature (see description of the -gnatV flag in the users
guide) in conjunction with pragma Initialize_Scalars provides a
powerful new tool to assist in the detection of problems caused by
uninitialized variables. 

---end-quote---

We can assure everyone that from a developers and testers point of view
the combination of Initialize_Scalars and enhanced validity checking is
indeed "particularly useful".

References:
[1] <http://www.cs.kuleuven.be/~dirk/papers/ae02cfmu-paper.pdf>
[2] <http://www.springer.de/cgi/svcat/search_book.pl?isbn=3-540-43784-3>
[3] <http://www.adacore.com/wp-content/files/auto_update/gnat-unw-docs/html/gnat_rm_2.html#SEC48>
[4] <http://www.adacore.com/wp-content/files/auto_update/gnat-unw-docs/html/gnat_ugn_4.html#SEC47>

Dirk
Dirk.Craeynest@cs.kuleuven.be (for Ada-Belgium/-Europe/SIGAda/WG9 mail)

*** 11th Intl.Conf.on Reliable Software Technologies - Ada-Europe'2006
*** June 5-9, 2006 ** Porto, Portugal ** http://www.ada-europe.org ***



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

* Re: Handling invalid objects
  2006-03-18  3:21             ` Handling invalid objects Justin Gombos
  2006-03-18  7:35               ` Jeffrey R. Carter
@ 2006-03-18  8:57               ` Jacob Sparre Andersen
  2006-03-19 19:07                 ` Dr. Adrian Wrigley
  2006-03-19 22:06               ` Brian May
  2006-03-20 23:44               ` Randy Brukardt
  3 siblings, 1 reply; 94+ messages in thread
From: Jacob Sparre Andersen @ 2006-03-18  8:57 UTC (permalink / raw)


Justin Gombos wrote:

> The 'Valid attribute exists to be able to handle abnormal objects.
>
> Here's a concrete example.  Suppose I have:
>
>   type clock_type is mod 12;
>
>   function hour_of_day return clock_type;
>
> If hour_of_day gets called and for whatever reason I cannot return
> an hour_of_day, the caller needs to know that.  Exceptions are a
> poor choice.  The quality and style guide advises against them for a
> good reason; exceptions are like gotos - and produce a questionable
> state.  It would be more graceful for me to return an invalid value
> (like -1), so my caller can simply do a 'Valid to discover whether
> the operation was successful.

No.  The way to do that is to have proper values for all the states
you want to handle, i.e.:

   type Hours is mod 12;

   type Clock_Type (Is_Set : Boolean := False) is new
      record
         case Is_Set is
            when True =>
               Time : Hours;
            when False =>
               null;
         end case;
      end record;

Greetings,

Jacob
-- 
ACRONYM: A Contrived Reduction Of Nomenclature Yielding Mnemonics



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

* Re: private types
  2006-03-17 23:36         ` Justin Gombos
  2006-03-18  1:32           ` Randy Brukardt
@ 2006-03-18  9:20           ` Dmitry A. Kazakov
  1 sibling, 0 replies; 94+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-18  9:20 UTC (permalink / raw)


On Fri, 17 Mar 2006 23:36:05 GMT, Justin Gombos wrote:

> BTW- I sometimes have a use for creating an abnormal object, and find
>      Ada lacking in not providing such a mechanism.  I'm sometimes
>      forced to either include abnormal values in the set of values
>      declared for a type, or to have a seperate flag.  Both of these
>      are messy.  Why not have a 'invalid function added to Ada to
>      enable simple and explicit initialization of abnormal objects?

As Randy have pointed out, there is a great difference between faults and
bugs. If we stay in the realm of correct programs, then the mechanism you
are asking for is subtyping. One can exclude some values by putting a
subtype constraint on the base type.

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



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

* Re: private types
  2006-03-17 23:44         ` Justin Gombos
@ 2006-03-18  9:24           ` Dmitry A. Kazakov
  2006-03-18 12:56           ` Robert A Duff
  1 sibling, 0 replies; 94+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-18  9:24 UTC (permalink / raw)


On Fri, 17 Mar 2006 23:44:08 GMT, Justin Gombos wrote:

> On 2006-03-17, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
>> Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:
>>
>> I'm not sure what the right answer is, but surely all the arguments
>> for and against dummy values apply equally to access types.
> 
> I don't agree with that.  Null is a standard abnormal object for
> access types in all languages, and can never be taken for something
> valid.

No. Null is a legal access value. You can compare, copy, assign null
pointers. You *can* dereference them! It is just so, that the effect of
this operation would be Constraint_Error.

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



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

* Re: private types
  2006-03-18  1:17         ` Randy Brukardt
  2006-03-18  2:17           ` Justin Gombos
  2006-03-18  8:39           ` Uninitialized variables (was: Re: private types) Dirk Craeynest
@ 2006-03-18 12:06           ` Martin Dowie
  2006-03-18 12:47           ` Robert A Duff
  3 siblings, 0 replies; 94+ messages in thread
From: Martin Dowie @ 2006-03-18 12:06 UTC (permalink / raw)


Randy Brukardt wrote:
> It's not just testing. Ada 95 is very clear that an Ada compiler cannot
> assume an object is in range unless it can prove it is initialized. Explicit
> initialization makes this proof trivial (and leaving it out may make it
> impossible to prove.) Thus, given
>     A : Positive := 10;
>     B : Positive;
> the compiler can assume that A is in range, potentially being able to
> eliminate checks and speeding up the code. But it cannot assume that B is in
> range (unless it can prove that it is initialized further on).
> 
> So I recommend initalizing everything (or assigning it immediately after the
> begin) that could be significant to performance.


Or use a tool like PolySpace, which is very good at spotting this sort 
of thing. (www.polyspace.com).

Cheers

-- Martin



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

* Re: private types
  2006-03-18  1:17         ` Randy Brukardt
                             ` (2 preceding siblings ...)
  2006-03-18 12:06           ` private types Martin Dowie
@ 2006-03-18 12:47           ` Robert A Duff
  3 siblings, 0 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-18 12:47 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> It's not just testing. Ada 95 is very clear that an Ada compiler cannot
> assume an object is in range unless it can prove it is initialized.

This is not quite true.  What the compiler can prove depends on the
compiler's code generation strategy.  Example:

    type Index is range 1..10;
    type A is array(Index) of Character;

    X: Index; -- not initialized here

    procedure P(Y: Index) is
    begin
        ...
    end P;

    ... -- (*) might initialize X here

    P(X);

Suppose the compiler cannot prove that the code marked "-- (*)"
will initialize X.  The compiler has a choice:  It can do
a range check at the call to P, and then assume inside the body
of P that Y is in range (even though the value _might_ have
come from an uninitialized variable).  Or, the compiler can
avoid the range check on the call to P, in which case it cannot
assume that Y is in range.

> So I recommend initalizing everything (or assigning it immediately after the
> begin) that could be significant to performance.

That also depends on the compiler.  Many compilers can prove that a
variable is initialized here:

    begin
        if ... then
            A := 3;
        else
            A := 4;
        end if;
        ... -- Here, we can presume A is in range.

Adding "A := 0;" between "begin" and "if" would be overkill
for such compilers.

- Bob



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

* Re: private types
  2006-03-17 23:44         ` Justin Gombos
  2006-03-18  9:24           ` Dmitry A. Kazakov
@ 2006-03-18 12:56           ` Robert A Duff
  2006-03-18 15:06             ` Justin Gombos
  1 sibling, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-18 12:56 UTC (permalink / raw)


Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

> On 2006-03-17, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
> > Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:
> >
> > I'm not sure what the right answer is, but surely all the arguments
> > for and against dummy values apply equally to access types.
> 
> I don't agree with that.  Null is a standard abnormal object for
> access types in all languages, and can never be taken for something
> valid.

Null is neither "abnormal" nor "invalid" in Ada.  As for "all
languages", some have a concept of "null" or "nil" or whatever that is
the same in this regard.  Some languages have no such concept.

In Ada, if an object of an access type has no explicit initial value,
you can't easily tell whether that means "null is a meaningful value for
this variable, and that's the default I want" versus "this variable will
be initialized to a meaningful (non-null) value later".

This is exactly analogous to the case with integers -- if they were
default-initialized to zero, you can't easily tell whether zero is
intended as a meaningful initial value, versus later initialization to a
meaningful value.

- Bob



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

* Re: Uninitialized variables (was: Re: private types)
  2006-03-18  8:39           ` Uninitialized variables (was: Re: private types) Dirk Craeynest
@ 2006-03-18 14:06             ` Gautier
  2006-03-18 14:36               ` Uninitialized variables Jeffrey Creem
  2006-03-21  0:22             ` Uninitialized variables (was: Re: private types) Randy Brukardt
  2006-03-21  0:38             ` Randy Brukardt
  2 siblings, 1 reply; 94+ messages in thread
From: Gautier @ 2006-03-18 14:06 UTC (permalink / raw)


Here (trying to to sum up), 3 problems I see with the tactic of
initializing everything:

 - useless initializations (i.e. dummy values rewritten later) take
time and usually _hurt_ performance (think to number crunching with
huge objects, or frequently used functions with local variables)
 - useless initializations introduce meaningless code lines
 - [Dirk] useless initializations prevent detecting bugs that can be
detected without these initializations (they can be detected by
combining the Initialize_Scalars pragma and the validity checks)

My rule is rather to initialize _only_ variables you can give a
meaningful values.
Of course it depends on the context. Maybe there are situations where
you can prefer a program giving wrong results than an unhandled
exception popping at the wrong moment (although I find the method very
shocking!)... In such cases the systematic initialization could be a
way (not nice but pragmatic) to silently disable bug detection.
_______________________________________________________________ 
Gautier         -- http://www.mysunrise.ch/users/gdm/index.htm 
Ada programming -- http://www.mysunrise.ch/users/gdm/gsoft.htm 

NB: For a direct answer, e-mail address on the Web site!



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

* Re: Uninitialized variables
  2006-03-18 14:06             ` Gautier
@ 2006-03-18 14:36               ` Jeffrey Creem
  0 siblings, 0 replies; 94+ messages in thread
From: Jeffrey Creem @ 2006-03-18 14:36 UTC (permalink / raw)


Gautier wrote:
> Here (trying to to sum up), 3 problems I see with the tactic of
> initializing everything:
> 
>  - useless initializations (i.e. dummy values rewritten later) take
> time and usually _hurt_ performance (think to number crunching with
> huge objects, or frequently used functions with local variables)
>  - useless initializations introduce meaningless code lines
>  - [Dirk] useless initializations prevent detecting bugs that can be
> detected without these initializations (they can be detected by
> combining the Initialize_Scalars pragma and the validity checks)
> 
> My rule is rather to initialize _only_ variables you can give a
> meaningful values.

This is also the approach I follow. It has the added benefit that some 
compilers can now give you warnings about reading from it before you 
assign to it and thus help you find the bug. If one does the typical 
initialize everything to 0 or 'first or something like that then you can 
expect no help from the compiler.

Now in reality, compilers vary in their ability to provide useful 
warnings in this area.

GNAT does a reasonably good job of balancing real warnings in this case 
against false warnings.

Another compiler I use takes a different approach where it seems to warn 
in a lot more cases and thus ends up with a lot more false positives.
It is probably not that bad of an approach if you used this compiler 
from the beginning but with lots of lecagy code the signal to noise 
ratio of these warnings is so poor that I have not really found an 
effective way to make use of the warnings.


Consider the following toy code:

with Text_IO;
procedure Toy is

   I : Integer;
   I_Set : Boolean := False;
   Should_We_Set_I : Character;
   J : Integer;

begin

   Text_Io.Get(Should_We_Set_I);

   if Should_We_Set_I = 'y' then
     I_Set := True;
     I := 1;
   end if;


   if I_Set then
     Text_Io.Put_Line(Integer'Image(I));  -- This is ok
     Text_IO.Put_Line(Integer'image(J));  -- This is bad
   end if;

   J := 1;

end Toy;


GNAT Warns on the line that says This is bad but not on the line that 
says this is ok.

Another compiler I use warns on both (Not posting other compiler here 
only because I have not tested this exact code on it and am making this 
assertion based on similar real code).


Obviously, unless one uses someting like polyspace, a simple compiler 
can't be expected to detect all of these path flow type cases.


The important point here is that if one had a convention that all 
variables should be initialized, no compiler could tell you that you 
were doing something wrong on the "this is bad line".





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

* Re: private types
  2006-03-18 12:56           ` Robert A Duff
@ 2006-03-18 15:06             ` Justin Gombos
  2006-03-19  9:35               ` Martin Krischik
  2006-03-25 21:40               ` Robert A Duff
  0 siblings, 2 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-18 15:06 UTC (permalink / raw)


On 2006-03-18, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
>
> In Ada, if an object of an access type has no explicit initial
> value, you can't easily tell whether that means "null is a
> meaningful value for this variable, and that's the default I want"
> versus "this variable will be initialized to a meaningful (non-null)
> value later".

If you want to distinguish between the two possiblities, you could
explicitly initialize your pointers to null in the first case, and not
in the second.  I rarely use access types, and I probably wouldn't do
that myself simply because I find the distinction unimportant for
access types.  Regardless, I'm not going to give up the benefit of
having this distinction on non-access scalars simply because my access
type declarations don't have it.

> This is exactly analogous to the case with integers -- if they were
> default-initialized to zero, you can't easily tell whether zero is
> intended as a meaningful initial value, versus later initialization
> to a meaningful value.

Integers, and other non-access scalars are different in this case
because you cannot expect zero to have the same meaning.  Zero has a
universal meaning with access types, but it could be in range or out
of range for any other type.  The ARM selects access types
specifically to get a default initialization of zero for this reason.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: Handling invalid objects
  2006-03-18  7:35               ` Jeffrey R. Carter
@ 2006-03-18 16:10                 ` Justin Gombos
  2006-03-19 11:00                   ` Simon Wright
  2006-03-20 23:57                   ` Randy Brukardt
  0 siblings, 2 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-18 16:10 UTC (permalink / raw)


On 2006-03-18, Jeffrey R. Carter <spam.not.jrcarter@acm.not.spam.org> wrote:
>
> There's a basic SW-engineering principle that one thing should have
> one meaning.  Using one thing with 2 meanings, which is what you're
> asking for, clearly violates that principle.

That's a good point.  Given that perspective, would you say the
practice of using null access values to indicate whether the access
value is useable violates this principle?

>>   type clock_type is mod 12;
>> 
>>   function hour_of_day return clock_type;
>
> This seems to specify a function that is expected to always be able
> to return a valid value. 

Pretend that there are cases where the hour of day is unavailable.  I
chose an example using mod only because it has added complications
when increasing the range of values to allow for an invalid object,
and hour of day is simple.

> If it is expected to only be able to return a valid value some of
> the time, that should be documented, probably by naming the function
> something like Try_To_Get_Hour_Of_Day.

There's that principle of naming non-boolean functions nouns, since
they return an object.  Also, if an API is often queried for
information that it cannot retrieve, and often this is normal
operation, subprogram prefixes like "try_to_get_" seem lengthy.  I
would have to use some other means to indicate that the returned value
may be unusable.

> If the function should always be able to return a valid value, and
> it can't, that is clearly an exceptional situation, and an exception
> is clearly the correct way to deal with such a situation.

I recall working to a coding standard that barred exception raising
when other mechanisms for error detection are possible.  It
effectively banned exception raising altogether because you can always
send an error notice by other means.  Exceptions are synonymous with
goto statements, with the additional effect of creating an
unpredictable state so I didn't challenge the rule.

Exception raising and handling is often viewed as writing code that
will never execute.  Predefined exceptions must be handled when there
is an expectation they will be raised, but their usefullness stops
there.  Beyond that, it's like writing erroneous code on purpose.

> If valid values are not always possible, then it's a question of how
> often they are not available. If it's a fairly common occurrence
> (and that can be less than 50% of the time), then it's not an
> exceptional situation, and an unconstrained record type with a
> Boolean discriminant is probably the best thing to return.  If, on
> the other hand, it's a rare occurrence, then it's still an
> exceptional situation, and an exception is the correct solution.

I try to avoid variant records, but this sounds like a good use for
them.  I'll have to try that.

> Anyone who has seen C code that correctly checks and deals with all
> returned error codes and success flags knows how complicated and
> unreadable such code is.  The common practice in C is to not do the
> necessary checks so that the code is simpler and more readable. That
> is clearly not an acceptable solution.  Exceptions separate the
> normal processing from the exceptional processing, allowing simple
> and readable code for the normal case while ensuring that all checks
> are performed and dealt with.
>
> There are cases where exceptions are outlawed; most of them are not
> justified.  Even if they were all justified, advocating a return to
> the mess that error codes create is not a viable option.

It's a mess regardless.  Clearly Ada is deficient in this respect, as
all languages seem to be.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-18 15:06             ` Justin Gombos
@ 2006-03-19  9:35               ` Martin Krischik
  2006-03-19 14:52                 ` Peter C. Chapin
                                   ` (2 more replies)
  2006-03-25 21:40               ` Robert A Duff
  1 sibling, 3 replies; 94+ messages in thread
From: Martin Krischik @ 2006-03-19  9:35 UTC (permalink / raw)


Justin Gombos wrote:

> Zero has a
> universal meaning with access types, but it could be in range or out
> of range for any other type. ï¿œThe ARM selects access types
> specifically to get a default initialization of zero for this reason.

Who says that Null := 16#0#? I could image a Hardware/CPU/OS where it would
be better to define Null := 16#FFFF_FFFF_FFFF_FFFF#.

For example an OS who's Virtual Memory Management System assign address
16#0# to be a valid address and to hold some important process data to
which the process needs access.

Of course programming C or C++ on such an OS could be quite challenging
(Write to (void*)0 and you mess up your Proccess Information Descriptor).

Martin 
-- 
mailto://krischik@users.sourceforge.net
Ada programming at: http://ada.krischik.com



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

* Re: Handling invalid objects
  2006-03-18 16:10                 ` Justin Gombos
@ 2006-03-19 11:00                   ` Simon Wright
  2006-03-20 23:57                   ` Randy Brukardt
  1 sibling, 0 replies; 94+ messages in thread
From: Simon Wright @ 2006-03-19 11:00 UTC (permalink / raw)


Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

> Exception raising and handling is often viewed as writing code that
> will never execute.  Predefined exceptions must be handled when
> there is an expectation they will be raised, but their usefullness
> stops there.  Beyond that, it's like writing erroneous code on
> purpose.

Code that _should_ never execute, perhaps!

Exceptions are for things that can't be handled locally because of
lack of application knowledge. For example, how to handle a
Socket_Error?

And also, I think, for contract violation, where the contract can;t be
enforced in the language. Now we can say 'not null access' but in
Ada95 we can't.

>> There are cases where exceptions are outlawed; most of them are not
>> justified.  Even if they were all justified, advocating a return to
>> the mess that error codes create is not a viable option.
>
> It's a mess regardless.  Clearly Ada is deficient in this respect,
> as all languages seem to be.

I think it's called living in the real world.



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

* Re: private types
  2006-03-19  9:35               ` Martin Krischik
@ 2006-03-19 14:52                 ` Peter C. Chapin
  2006-03-19 15:08                   ` Björn Persson
  2006-03-19 18:15                 ` Robert A Duff
  2006-03-19 19:27                 ` Jeffrey R. Carter
  2 siblings, 1 reply; 94+ messages in thread
From: Peter C. Chapin @ 2006-03-19 14:52 UTC (permalink / raw)


Martin Krischik <krischik@users.sourceforge.net> wrote in
news:1259548.CMTukHGvVZ@linux1.krischik.com: 

> Of course programming C or C++ on such an OS could be quite
> challenging (Write to (void*)0 and you mess up your Proccess
> Information Descriptor). 

The C/C++ standard does not require NULL pointers to be represented by all 
zero bits either. The null pointer constant, (void*)0, might be translated 
into 0xFFFFFFFF or some other value.

Peter



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

* Re: private types
  2006-03-19 14:52                 ` Peter C. Chapin
@ 2006-03-19 15:08                   ` Björn Persson
  2006-03-19 16:34                     ` Martin Krischik
                                       ` (2 more replies)
  0 siblings, 3 replies; 94+ messages in thread
From: Björn Persson @ 2006-03-19 15:08 UTC (permalink / raw)


Peter C. Chapin wrote:
> Martin Krischik <krischik@users.sourceforge.net> wrote in
> news:1259548.CMTukHGvVZ@linux1.krischik.com: 
>>Of course programming C or C++ on such an OS could be quite
>>challenging (Write to (void*)0 and you mess up your Proccess
>>Information Descriptor). 
> 
> The C/C++ standard does not require NULL pointers to be represented by all 
> zero bits either. The null pointer constant, (void*)0, might be translated 
> into 0xFFFFFFFF or some other value.

Well, does the standard require that (void*)0 == NULL? What if I wanted 
a pointer to address zero on this hypothetical OS? How would I get that 
if (void*)0 gets transformed to a non-zero NULL?

-- 
Bj�rn Persson                              PGP key A88682FD
                    omb jor ers @sv ge.
                    r o.b n.p son eri nu



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

* Re: private types
  2006-03-19 15:08                   ` Björn Persson
@ 2006-03-19 16:34                     ` Martin Krischik
  2006-03-20  9:57                       ` Maciej Sobczak
  2006-03-20 20:29                       ` Simon Wright
  2006-03-19 17:43                     ` Larry Kilgallen
  2006-03-19 22:11                     ` Peter C. Chapin
  2 siblings, 2 replies; 94+ messages in thread
From: Martin Krischik @ 2006-03-19 16:34 UTC (permalink / raw)


Bjï¿œrn Persson wrote:

> Peter C. Chapin wrote:
>> Martin Krischik <krischik@users.sourceforge.net> wrote in
>> news:1259548.CMTukHGvVZ@linux1.krischik.com:
>>>Of course programming C or C++ on such an OS could be quite
>>>challenging (Write to (void*)0 and you mess up your Proccess
>>>Information Descriptor).
>> 
>> The C/C++ standard does not require NULL pointers to be represented by
>> all zero bits either. The null pointer constant, (void*)0, might be
>> translated into 0xFFFFFFFF or some other value.
> 
> Well, does the standard require that (void*)0 == NULL?

Before I learned C++ in deeps I thought the same. But then I read that the
use of #define NULL is depreciated C++ and that one should use a simple 0
instead.

> What if I wanted 
> a pointer to address zero on this hypothetical OS?

That too is an interesting point. Actually dereference to (char*)0 is not
forbidden - you will get the content of memory element 0x0. And when I did
C work on systems without an MMU and the memory protection this was a
serious problem. (char*)NULL would return data.

Modern OS don't map the first memory page to the process so access will
result in an error. But they only do that to ease up C/C++ development.
There is no other reason.

> How would I get that 
> if (void*)0 gets transformed to a non-zero NULL?

Interesting question.

Martin
-- 
mailto://krischik@users.sourceforge.net
Ada programming at: http://ada.krischik.com



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

* Re: private types
  2006-03-19 15:08                   ` Björn Persson
  2006-03-19 16:34                     ` Martin Krischik
@ 2006-03-19 17:43                     ` Larry Kilgallen
  2006-03-19 22:11                     ` Peter C. Chapin
  2 siblings, 0 replies; 94+ messages in thread
From: Larry Kilgallen @ 2006-03-19 17:43 UTC (permalink / raw)


In article <1172812.9zPbPKbdVq@linux1.krischik.com>, Martin Krischik <krischik@users.sourceforge.net> writes:

> Modern OS don't map the first memory page to the process so access will
> result in an error. But they only do that to ease up C/C++ development.
> There is no other reason.

Some operating systems map the first memory page to the process to aid
LISP development.  Pity the person whose program uses both languages.



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

* Re: private types
  2006-03-19  9:35               ` Martin Krischik
  2006-03-19 14:52                 ` Peter C. Chapin
@ 2006-03-19 18:15                 ` Robert A Duff
  2006-03-19 19:20                   ` Martin Krischik
  2006-03-19 19:27                 ` Jeffrey R. Carter
  2 siblings, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-19 18:15 UTC (permalink / raw)


Martin Krischik <krischik@users.sourceforge.net> writes:

> Justin Gombos wrote:
> 
> > Zero has a
> > universal meaning with access types, but it could be in range or out
> > of range for any other type. ï¿œThe ARM selects access types
> > specifically to get a default initialization of zero for this reason.
> 
> Who says that Null := 16#0#? I could image a Hardware/CPU/OS where it would
> be better to define Null := 16#FFFF_FFFF_FFFF_FFFF#.

The convention on TOPS-20 for null (in all the various languages that
have it) is to use some address other than zero.  I don't remember
which address.  The OS protects that page so it traps
(just as most modern operating systems do for page zero).

There was even an Ada compiler for TOPS-20, and of course it obeyed that
convention.

Using all-zero-bits for null has some minor efficiency advantages.

> For example an OS who's Virtual Memory Management System assign address
> 16#0# to be a valid address and to hold some important process data to
> which the process needs access.
> 
> Of course programming C or C++ on such an OS could be quite challenging
> (Write to (void*)0 and you mess up your Proccess Information Descriptor).

I believe the C++ rule is that 0 (written in your program) is the same
thing as NULL -- but it need not be represented internally by
all-zero-bits.  Casting the integer zero to a pointer, however,
does not necessarily result in NULL.  That's sort of confusing,
but if you understand the rules, the "quite challenging" comment
above does not hold.

- Bob



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

* Re: Handling invalid objects
  2006-03-18  8:57               ` Jacob Sparre Andersen
@ 2006-03-19 19:07                 ` Dr. Adrian Wrigley
  2006-03-20 15:25                   ` Robert A Duff
  0 siblings, 1 reply; 94+ messages in thread
From: Dr. Adrian Wrigley @ 2006-03-19 19:07 UTC (permalink / raw)


On Sat, 18 Mar 2006 09:57:24 +0100, Jacob Sparre Andersen wrote:

> Justin Gombos wrote:
> 
>> The 'Valid attribute exists to be able to handle abnormal objects.
>>
>> Here's a concrete example.  Suppose I have:
>>
>>   type clock_type is mod 12;
>>
>>   function hour_of_day return clock_type;
>>
>> If hour_of_day gets called and for whatever reason I cannot return
>> an hour_of_day, the caller needs to know that.  Exceptions are a
>> poor choice.  The quality and style guide advises against them for a
>> good reason; exceptions are like gotos - and produce a questionable
>> state.  It would be more graceful for me to return an invalid value
>> (like -1), so my caller can simply do a 'Valid to discover whether
>> the operation was successful.
> 
> No.  The way to do that is to have proper values for all the states
> you want to handle, i.e.:
> 
>    type Hours is mod 12;
> 
>    type Clock_Type (Is_Set : Boolean := False) is new
>       record
>          case Is_Set is
>             when True =>
>                Time : Hours;
>             when False =>
>                null;
>          end case;
>       end record;

This is exactly the way I would expect this problem would be solved.
It's one of the reasons for variant records.  But it is still
a bit messy (more verbose, extra component in names).
Writing a generic just for one type is even more verbose, but in
some fields you have a lot of invalid data around!

In my field of stock trading, time series often have holes,
probably erroneous values, and other problems and discrepencies.
Tracking bad data, while keeping the code simple would be nice!

It'd be great if the language allowed me to set and propagate
invalid values naturally!  With floating point, a NaN is the
obvious choice.  When you see NaNs output by your code, you
know some/all of the calculation didn't work out properly.
With access types, null can sometimes be used this way.  But
a proper invalid value would be useful.  With integers, it
would seem very sensible to have a NaN as well.  Why did floats
get a NaN value, but integers didn't?  Languages often try to give
facilities that can map onto hardware efficiently.  But hardware
tries to give exactly what the languages need, but no more.
I think this vicious circle has made innovation with invalid
values hard, in spite of the usefulness in software design,
as well as hardware and software integrity.

Of course, back in the olden days, some machines (which?) had
ECC hardware, which generated an exception when invalid data was
fetched from memory, and programs could deliberately write invalid
bit patterns.  This could be exploited to catch bugs and keep
bad data from corrupting execution.  Nowadays, you can't do this
because the invalid bit patterns don't propagate through VM
and cache subsytems (even although caches and backing stores have
their own ECC).

VHDL, when modelling hardware logic has a comprehensive system
for tracking invalid values.  Often the invalid data is
irrelevant to the operation and valid data prevails.  Sometimes,
invalid data propagates and dominates.  Raising exceptions
all over the place cannot be a complete substitute.  Only by building
in data validity into the core of the language and/or hardware can you get
widespread adoption.  IEEE Floating Point shows it can be useful,
inexpensive and ubiquitious.  Programming guidelines, generic validity
wrappers and compiler options are a poor alternative.
--
Adrian




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

* Re: private types
  2006-03-19 18:15                 ` Robert A Duff
@ 2006-03-19 19:20                   ` Martin Krischik
  2006-03-19 20:43                     ` Dr. Adrian Wrigley
  2006-03-20  9:40                     ` Maciej Sobczak
  0 siblings, 2 replies; 94+ messages in thread
From: Martin Krischik @ 2006-03-19 19:20 UTC (permalink / raw)


Robert A Duff wrote:

> I believe the C++ rule is that 0 (written in your program) is the same
> thing as NULL -- but it need not be represented internally by
> all-zero-bits. ï¿œCasting the integer zero to a pointer, however, 
> does not necessarily result in NULL. ï¿œThat's sort of confusing,
> but if you understand the rules, the "quite challenging" comment
> above does not hold.

Super! And how many (in %) of C++ programmer actually know that. By guess is
0.1%. And indeed I is the main problem: Only a very few C/C++ programmers
actually master the language. 

Martin 
-- 
mailto://krischik@users.sourceforge.net
Ada programming at: http://ada.krischik.com



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

* Re: private types
  2006-03-19  9:35               ` Martin Krischik
  2006-03-19 14:52                 ` Peter C. Chapin
  2006-03-19 18:15                 ` Robert A Duff
@ 2006-03-19 19:27                 ` Jeffrey R. Carter
  2 siblings, 0 replies; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-19 19:27 UTC (permalink / raw)


Martin Krischik wrote:
> 
> Of course programming C or C++ on such an OS could be quite challenging
> (Write to (void*)0 and you mess up your Proccess Information Descriptor).

Programming C/++ on all OSes is quite challenging, by definition.

-- 
Jeff Carter
"What I wouldn't give for a large sock with horse manure in it."
Annie Hall
42



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

* Re: private types
  2006-03-19 19:20                   ` Martin Krischik
@ 2006-03-19 20:43                     ` Dr. Adrian Wrigley
  2006-03-20 15:01                       ` Robert A Duff
  2006-03-27  4:07                       ` Dave Thompson
  2006-03-20  9:40                     ` Maciej Sobczak
  1 sibling, 2 replies; 94+ messages in thread
From: Dr. Adrian Wrigley @ 2006-03-19 20:43 UTC (permalink / raw)


On Sun, 19 Mar 2006 20:20:52 +0100, Martin Krischik wrote:

> Robert A Duff wrote:
> 
>> I believe the C++ rule is that 0 (written in your program) is the same
>> thing as NULL -- but it need not be represented internally by
>> all-zero-bits. �Casting the integer zero to a pointer, however, 
>> does not necessarily result in NULL. �That's sort of confusing,
>> but if you understand the rules, the "quite challenging" comment
>> above does not hold.
> 
> Super! And how many (in %) of C++ programmer actually know that. By guess is
> 0.1%. And indeed I is the main problem: Only a very few C/C++ programmers
> actually master the language. 

It is (or was) quite a common interview question, to see if
C (and C++) programmers know their subject properly.  As you
say, Robert, most don't.

A related topic is the issue of pointer representation, which
(IIRC) says that pointers to char (any kind) and void have to be
the same.  Pointers to functions have to be the same.  But all
other pointers can have their own representation.  All pointers
can be converted to and from pointers to void, without loss.  And
pointers can have different sizes and different patterns for the
null pointer.  I suspect a lot of code would fail if compilers
wanted to exercise their full freedoms!
--
Adrian




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

* Re: Handling invalid objects
  2006-03-18  3:21             ` Handling invalid objects Justin Gombos
  2006-03-18  7:35               ` Jeffrey R. Carter
  2006-03-18  8:57               ` Jacob Sparre Andersen
@ 2006-03-19 22:06               ` Brian May
  2006-03-20 21:17                 ` Jeffrey R. Carter
  2006-03-20 23:44               ` Randy Brukardt
  3 siblings, 1 reply; 94+ messages in thread
From: Brian May @ 2006-03-19 22:06 UTC (permalink / raw)


>>>>> "Justin" == Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

    Justin> The 'Valid attribute exists to be able to handle abnormal
    Justin> objects.

    Justin> Here's a concrete example.  Suppose I have:

    Justin> type clock_type is mod 12;

    Justin> function hour_of_day return clock_type;

    Justin> If hour_of_day gets called and for whatever reason I
    Justin> cannot return an hour_of_day, the caller needs to know
    Justin> that.  Exceptions are a poor choice.  The quality and
    Justin> style guide advises against them for a good reason;
    Justin> exceptions are like gotos - and produce a questionable
    Justin> state.  It would be more graceful for me to return an
    Justin> invalid value (like -1), so my caller can simply do a
    Justin> 'Valid to discover whether the operation was successful.

If you returned an invalid value, I would consider that a breach of
the contract you established where you declare you only return a valid
clock_type.

This is similar to a problem I have seen when tutoring C++, students
get stuck on the problem that looks something like this:

item &find_item(...) {
     
     ... search for item ...

     if (found) {
        return item;
     } else {
        return ????;
     }
}

The ideal solution would be exceptions, but the students haven't been
taught exceptions yet when conducting this exercise.

Another solution would be to change the API to return a struct value,
but students are told they cannot change the API.

So students typically hard code it to return the first item, on the
assumption that there is a first item. Either that, or simply omit the
return statement, and ignore the compiler warning. Not good
programming practise either way...
-- 
Brian May <bam@snoopy.apana.org.au>



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

* Re: private types
  2006-03-19 15:08                   ` Björn Persson
  2006-03-19 16:34                     ` Martin Krischik
  2006-03-19 17:43                     ` Larry Kilgallen
@ 2006-03-19 22:11                     ` Peter C. Chapin
  2 siblings, 0 replies; 94+ messages in thread
From: Peter C. Chapin @ 2006-03-19 22:11 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 568 bytes --]

Bj�rn Persson <spam-away@nowhere.nil> wrote in
news:SteTf.48935$d5.205176@newsb.telia.net: 

> Well, does the standard require that (void*)0 == NULL? What if I
> wanted a pointer to address zero on this hypothetical OS? How would I
> get that if (void*)0 gets transformed to a non-zero NULL?

I'd have to review the precise definition of the null pointer constant. 
Anything other than that is treated in the "usual" way. So for example, 
this might work

const int p = 0;

...  (void*)p ...

Or maybe you need to take the 'const' off the declaration of p.

Peter



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

* Re: private types
  2006-03-19 19:20                   ` Martin Krischik
  2006-03-19 20:43                     ` Dr. Adrian Wrigley
@ 2006-03-20  9:40                     ` Maciej Sobczak
  2006-03-20 15:09                       ` Robert A Duff
  1 sibling, 1 reply; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-20  9:40 UTC (permalink / raw)


Martin Krischik wrote:

> Only a very few C/C++ programmers
> actually master the language. 

As is true for any language that is at least moderately useful.


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: private types
  2006-03-19 16:34                     ` Martin Krischik
@ 2006-03-20  9:57                       ` Maciej Sobczak
  2006-03-20 10:58                         ` Peter C. Chapin
                                           ` (3 more replies)
  2006-03-20 20:29                       ` Simon Wright
  1 sibling, 4 replies; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-20  9:57 UTC (permalink / raw)


Martin Krischik wrote:

>>Well, does the standard require that (void*)0 == NULL?
> 
> Before I learned C++ in deeps I thought the same. But then I read that the
> use of #define NULL is depreciated C++ and that one should use a simple 0
> instead.

Where did you read this?
NULL is not depreciated. It's defined in the <cstddef> header to be a 
null-pointer constant, which is any integral const expression that 
evaluates to 0. Possible definition is:

#define NULL 0

Note: the following is explicitly prohibited:

#define NULL (void*)0

but still, (void*)0 == NULL will always evaluate to true, even if the 
internal representation of the null pointer is not zero.


>>What if I wanted 
>>a pointer to address zero on this hypothetical OS?
> 
> That too is an interesting point. Actually dereference to (char*)0 is not
> forbidden - you will get the content of memory element 0x0.

Not necessarily. It depends on what is the internal representation of 
the null pointer.


One of the possible ways to *really* get at address 0x0 is to do 
reinterpret_cast or use a union with the same effect. Usual cast 
notation as the one above will not do.

>>How would I get that 
>>if (void*)0 gets transformed to a non-zero NULL?
> 
> Interesting question.

The interesting question is why it might make any difference to you?
The only thing that really matters is that the null pointer is distinct 
from any other valid pointer, in which case it's equivalent to Ada's 
null. If you need more knowledge than this, then either you are doing 
something wrong, or you work in the application domain where you really 
need an intimate knowledge of all the parts of the underlying platform - 
including your compiler - in which case your above worries are gone anyway.


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: private types
  2006-03-20  9:57                       ` Maciej Sobczak
@ 2006-03-20 10:58                         ` Peter C. Chapin
  2006-03-20 11:19                           ` Peter C. Chapin
  2006-03-20 13:06                           ` Maciej Sobczak
  2006-03-20 15:19                         ` Robert A Duff
                                           ` (2 subsequent siblings)
  3 siblings, 2 replies; 94+ messages in thread
From: Peter C. Chapin @ 2006-03-20 10:58 UTC (permalink / raw)


Maciej Sobczak <no.spam@no.spam.com> wrote in
news:dvlu9d$mg6$1@sunnews.cern.ch: 

> Where did you read this?
> NULL is not depreciated. It's defined in the <cstddef> header to be a 
> null-pointer constant, which is any integral const expression that 
> evaluates to 0. Possible definition is:
> 
> #define NULL 0
> 
> Note: the following is explicitly prohibited:
> 
> #define NULL (void*)0

This defintion of NULL is not workable in C++. This is because C++ does 
not allow pointers to void to be put into other pointer types without a 
cast. If the above definition was used the following would be an error:

int *p = NULL;

Thus in C++, NULL must be defined as the literal "0". Note that this 
issue does not come up in C because C's type system is more permissive. 
Thus the (void*)0 is often used in C.

Because "NULL" just expands to "0" in C++, code using NULL can at times 
be misleading. For example consider

void f(int);
void f(char *);

f(NULL);  // Ambiguous, could call either f(int) or f(char *).

This is a surprising error. Other surprises come up when passing NULL to 
functions taking a variable number of arguments. Type checking is 
essentially turned off for the variable arguments and thus if integers 
and pointers have different representations or if the NULL pointer must 
be handled in a special way (not all bits zero), errors can occur

printf("The address is: %p\n", NULL);

In C++ this passes the integer zero to printf, not a pointer. The 
compiler can't understand that "0" is a null pointer constant in this 
context because it doesn't know what type the second argument to printf 
is supposed to be.

For these reasons many C++ experts recommend using "0" explicitly to 
represent NULL pointers and not the symbol NULL. This makes the problems 
above more apparent in the source and thus more likely that the 
programmer will notice them.

Peter



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

* Re: private types
  2006-03-20 10:58                         ` Peter C. Chapin
@ 2006-03-20 11:19                           ` Peter C. Chapin
  2006-03-20 13:06                           ` Maciej Sobczak
  1 sibling, 0 replies; 94+ messages in thread
From: Peter C. Chapin @ 2006-03-20 11:19 UTC (permalink / raw)


"Peter C. Chapin" <pchapin@sover.net> wrote in 
news:Xns978C3CC16F9D7pchapinsovernet@198.186.192.137:

> Maciej Sobczak <no.spam@no.spam.com> wrote in
> news:dvlu9d$mg6$1@sunnews.cern.ch: 
> 
>> Note: the following is explicitly prohibited:

Let me apologize for my last posting... I had read the above as "the 
following is explicitly *permitted*". I need to read a little more 
carefully in the future!

Peter



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

* Re: private types
  2006-03-20 10:58                         ` Peter C. Chapin
  2006-03-20 11:19                           ` Peter C. Chapin
@ 2006-03-20 13:06                           ` Maciej Sobczak
  1 sibling, 0 replies; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-20 13:06 UTC (permalink / raw)


Peter C. Chapin wrote:

>>Note: the following is explicitly prohibited:
>>
>>#define NULL (void*)0
> 
> This defintion of NULL is not workable in C++.

Which we've already cleared. :)


> Thus in C++, NULL must be defined as the literal "0".

Not exactly. It can be anything that is an integral constant expression 
evalutating to zero. Thus, "0" is one obvious choice, but not any better 
than, say, "0L", "'\0'" or even "(125 - 5 * 5 * 5)".


> Because "NULL" just expands to "0" in C++, code using NULL can at times 
> be misleading. For example consider
> 
> void f(int);
> void f(char *);
> 
> f(NULL);  // Ambiguous, could call either f(int) or f(char *).
> 
> This is a surprising error.

That's why one of the sweeties in the upcoming C++ standard is a new 
keyword nullptr, which will be useable only in those contexts where a 
pointer type is expected, so that:

f(nullptr);

will always choose the second overload from the above.

> Other surprises come up when passing NULL to 
> functions taking a variable number of arguments.

Such functions are FUBARed anyway. :)

> For these reasons many C++ experts recommend using "0" explicitly to 
> represent NULL pointers and not the symbol NULL. This makes the problems 
> above more apparent in the source and thus more likely that the 
> programmer will notice them.

On the other hand, for the human reader "NULL" is immediately associated 
with some special pointer value, not with not-at-all-special integer, so 
that the following:

if (item != NULL) ...

is also immediately recognized as a test against *existence* of some 
item (which also implies that item is a pointer), not as a test against 
item's integer value. In such contexts I use NULL.

As you see, this subject has many faces.
I invite you to comp.lang.c++.moderated to discuss them in more depth.


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: private types
  2006-03-19 20:43                     ` Dr. Adrian Wrigley
@ 2006-03-20 15:01                       ` Robert A Duff
  2006-03-27  4:07                       ` Dave Thompson
  1 sibling, 0 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-20 15:01 UTC (permalink / raw)


"Dr. Adrian Wrigley" <amtw@linuxchip.demon.co.uk.uk.uk> writes:

> On Sun, 19 Mar 2006 20:20:52 +0100, Martin Krischik wrote:
> 
> > Robert A Duff wrote:
> > 
> >> I believe the C++ rule is that 0 (written in your program) is the same
> >> thing as NULL -- but it need not be represented internally by
> >> all-zero-bits. �Casting the integer zero to a pointer, however, 
> >> does not necessarily result in NULL. �That's sort of confusing,
> >> but if you understand the rules, the "quite challenging" comment
> >> above does not hold.
> > 
> > Super! And how many (in %) of C++ programmer actually know that. By guess is
> > 0.1%. And indeed I is the main problem: Only a very few C/C++ programmers
> > actually master the language. 
> 
> It is (or was) quite a common interview question, to see if
> C (and C++) programmers know their subject properly.  As you
> say, Robert, most don't.

Martin said that.  I have no idea how close his .1% estimate is
to the truth.  It's certainly true that many programmers learn
their programming languages by experiment -- what works is
all-too-often assumed to be what the language is.

- Bob



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

* Re: private types
  2006-03-20  9:40                     ` Maciej Sobczak
@ 2006-03-20 15:09                       ` Robert A Duff
  2006-03-21  8:07                         ` Maciej Sobczak
  0 siblings, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-20 15:09 UTC (permalink / raw)


Maciej Sobczak <no.spam@no.spam.com> writes:

> Martin Krischik wrote:
> 
> > Only a very few C/C++ programmers
> > actually master the language.
> 
> As is true for any language that is at least moderately useful.

True.  Language designers ought to take that into account -- whenever
possible, try to design features subtle misunderstandings are unlikely
to cause bugs.

Suppose an Ada programmer and a C++ programmer both think that null/NULL
must be represented as all-zero-bits.  Both programmers are confused.
But which programmer is more likely to write code that won't work
on a machine where the assumption turns out to be false?

- Bob



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

* Re: private types
  2006-03-20  9:57                       ` Maciej Sobczak
  2006-03-20 10:58                         ` Peter C. Chapin
@ 2006-03-20 15:19                         ` Robert A Duff
  2006-03-20 16:47                           ` James Dennett
  2006-03-20 19:12                         ` Martin Krischik
  2006-03-20 19:32                         ` Martin Krischik
  3 siblings, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-20 15:19 UTC (permalink / raw)


Maciej Sobczak <no.spam@no.spam.com> writes:

> but still, (void*)0 == NULL will always evaluate to true, even if the
> internal representation of the null pointer is not zero.

Are you sure?  Are you talking about C or C++ or both?

Does (void*)x always return NULL if x is an appropriate-sized integer
whose value is zero?  That would require run-time overhead if
NULL is not represented as all-zero-bits.

On the other hand, it's pretty confusing if casting zero to (void*)
is sometimes guaranteed to return NULL, and sometimes not, depending
on whether the zero value is known at compile time.

- Bob



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

* Re: Handling invalid objects
  2006-03-19 19:07                 ` Dr. Adrian Wrigley
@ 2006-03-20 15:25                   ` Robert A Duff
  0 siblings, 0 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-20 15:25 UTC (permalink / raw)


"Dr. Adrian Wrigley" <amtw@linuxchip.demon.co.uk.uk.uk> writes:

> It'd be great if the language allowed me to set and propagate
> invalid values naturally!

Well, it would be pretty inefficient if Booleans had an extra "invalid"
value, with or without hardware support.  Think about packed arrays of
Boolean.

Such a feature should be optional.

Some languages do support such things with lighter syntax than the
variant record somebody suggested earlier.

- Bob



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

* Re: private types
  2006-03-20 15:19                         ` Robert A Duff
@ 2006-03-20 16:47                           ` James Dennett
  0 siblings, 0 replies; 94+ messages in thread
From: James Dennett @ 2006-03-20 16:47 UTC (permalink / raw)


Robert A Duff wrote:
> Maciej Sobczak <no.spam@no.spam.com> writes:
> 
>> but still, (void*)0 == NULL will always evaluate to true, even if the
>> internal representation of the null pointer is not zero.
> 
> Are you sure?  Are you talking about C or C++ or both?

It's true for both, given the right interpretation of
(void*)0.

> Does (void*)x always return NULL if x is an appropriate-sized integer
> whose value is zero? 

Not necessarily.  But if x is a null pointer constant,
which to C++ means an integral constant expression with
value zero, then it will.  (C also allows an ICE of zero
cast to void*, so you have a NPC already.)

> That would require run-time overhead if
> NULL is not represented as all-zero-bits.

Yes, but that's not required.  You can get different
behaviour from

int i(0);
void *p((void*)i);

than from

int const i(0);
void *p((void*)i);

because for C++ the latter i is a valid integral constant
expression, while the former is not.

> On the other hand, it's pretty confusing if casting zero to (void*)
> is sometimes guaranteed to return NULL, and sometimes not, depending
> on whether the zero value is known at compile time.

Afraid so; generally C++ is arranged so that removing const,
where legal, should not change the meaning of code -- but
this is an exception, in theory at least.

-- James



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

* Re: private types
  2006-03-20  9:57                       ` Maciej Sobczak
  2006-03-20 10:58                         ` Peter C. Chapin
  2006-03-20 15:19                         ` Robert A Duff
@ 2006-03-20 19:12                         ` Martin Krischik
  2006-03-21  7:27                           ` Maciej Sobczak
  2006-03-20 19:32                         ` Martin Krischik
  3 siblings, 1 reply; 94+ messages in thread
From: Martin Krischik @ 2006-03-20 19:12 UTC (permalink / raw)


Maciej Sobczak wrote:

> Where did you read this?
> NULL is not depreciated. It's defined in the <cstddef> header to be a
> null-pointer constant, which is any integral const expression that
> evaluates to 0. Possible definition is:

But that is only a C compatibility header, only there to provide
compatibility C and one should avoid using them in pure C++?

Martin
-- 
mailto://krischik@users.sourceforge.net
Ada programming at: http://ada.krischik.com



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

* Re: private types
  2006-03-20  9:57                       ` Maciej Sobczak
                                           ` (2 preceding siblings ...)
  2006-03-20 19:12                         ` Martin Krischik
@ 2006-03-20 19:32                         ` Martin Krischik
  2006-03-21  7:41                           ` Maciej Sobczak
  3 siblings, 1 reply; 94+ messages in thread
From: Martin Krischik @ 2006-03-20 19:32 UTC (permalink / raw)


Maciej Sobczak wrote:

> The interesting question is why it might make any difference to you?
> The only thing that really matters is that the null pointer is distinct
> from any other valid pointer, in which case it's equivalent to Ada's
> null.

For C++ I can - barely - see that but C is supposed to system programming
language suitable for kernel and/or embedded progamming. Taking that into
account: How actually are the languages implementers to implement 
"distinct from any other valid pointer". If you are implementing a Ring 0
device driver on x86 all pointers are valid and on PC architecture there is
memory at (void*0) which one might want to access.

Martin
-- 
mailto://krischik@users.sourceforge.net
Ada programming at: http://ada.krischik.com



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

* Re: private types
  2006-03-19 16:34                     ` Martin Krischik
  2006-03-20  9:57                       ` Maciej Sobczak
@ 2006-03-20 20:29                       ` Simon Wright
  1 sibling, 0 replies; 94+ messages in thread
From: Simon Wright @ 2006-03-20 20:29 UTC (permalink / raw)


Martin Krischik <krischik@users.sourceforge.net> writes:

> Before I learned C++ in deeps I thought the same. But then I read
> that the use of #define NULL is depreciated C++ and that one should
> use a simple 0 instead.

deprecated (depreciation is what happens to a currency during inflation)



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

* Re: Handling invalid objects
  2006-03-19 22:06               ` Brian May
@ 2006-03-20 21:17                 ` Jeffrey R. Carter
  0 siblings, 0 replies; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-20 21:17 UTC (permalink / raw)


Brian May wrote:
> 
> item &find_item(...) {
>      
>      ... search for item ...
> 
>      if (found) {
>         return item;
>      } else {
>         return ????;
>      }
> }
> 
> The ideal solution would be exceptions, but the students haven't been
> taught exceptions yet when conducting this exercise.

No, exceptions are not ideal. Such a function may often be used in contexts 
where not finding a match is more common than finding one; the former case is 
not exceptional.

Consider a program like grep. It applies a regular-expression-matching function 
to every line in a file. It's quite common for > 80% of the matches to fail; 
that is not an exceptional situation. Using an exception to indicate no match 
would be incorrect.

Booch made this fundamental error in the regular expression matcher in his 
components book.

> Another solution would be to change the API to return a struct value,
> but students are told they cannot change the API.

Then what the student has is an incorrect specification that cannot be implemented.

-- 
Jeff Carter
"From this day on, the official language of San Marcos will be Swedish."
Bananas
28



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

* Re: Handling invalid objects
  2006-03-18  3:21             ` Handling invalid objects Justin Gombos
                                 ` (2 preceding siblings ...)
  2006-03-19 22:06               ` Brian May
@ 2006-03-20 23:44               ` Randy Brukardt
  2006-03-22  1:27                 ` Justin Gombos
  3 siblings, 1 reply; 94+ messages in thread
From: Randy Brukardt @ 2006-03-20 23:44 UTC (permalink / raw)


"Justin Gombos" <rpbkbq.xax.gld@uluv.kbq> wrote in message
news:41LSf.4126$TK2.1805@trnddc07...
> On 2006-03-18, Randy Brukardt <randy@rrsoftware.com> wrote:
> >
> > You're confusing an "invalid" object with an "abnormal"
> > object. Accessing an abnormal one is erroneous; surely you don't
> > want to intentionally put that into your programs. (Remember,
> > "erroneous" is Ada-speak for "anything at all can happen".)
>
> The 'Valid attribute exists to be able to handle abnormal objects.

No, it exists to handle *invalid* objects. It has no effect on *abnormal*
objects. Please be careful with your terminology here because using the
*abnormal* the way you are is very confusing. I'm using the terminology
defined in the Standard: see
http://www.adaic.com/standards/05aarm/html/AA-13-9-1.html (or the similar
section in the Ada 95 manual) to see the definitions of the terms.

> Here's a concrete example.  Suppose I have:

Your example shows *invalid* values, not *abnormal* values.

...
> Exceptions are a poor choice.

No, I think they're the right choice here (presuming you are talking about
clock failure or some other unusual event).

> The quality and style guide advises against them for a good
> reason; exceptions are like gotos - and produce a questionable state.

The state isn't questionable in this case: you have no legitimate value to
return, so anything you return is garbage. That means there isn't any state
to corrupt.

                        Randy.





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

* Re: Handling invalid objects
  2006-03-18 16:10                 ` Justin Gombos
  2006-03-19 11:00                   ` Simon Wright
@ 2006-03-20 23:57                   ` Randy Brukardt
  2006-03-22  2:06                     ` Justin Gombos
  1 sibling, 1 reply; 94+ messages in thread
From: Randy Brukardt @ 2006-03-20 23:57 UTC (permalink / raw)


"Justin Gombos" <rpbkbq.xax.gld@uluv.kbq> wrote in message
news:niWSf.1278$I7.339@trnddc03...
...
> I recall working to a coding standard that barred exception raising
> when other mechanisms for error detection are possible.  It
> effectively banned exception raising altogether because you can always
> send an error notice by other means. Exceptions are synonymous with
> goto statements, with the additional effect of creating an
> unpredictable state so I didn't challenge the rule.

You should have; such a coding standard is brain-damaged. Unless there is a
total ban on exceptions (as in SPARK -- and I disagree with SPARK on that),
there is no good reason to avoid exceptions. It's important that they not be
overused - especially in situations where it is normal and expected that the
failure occur (such as in a Find routine). But it's silly to avoid them,
even in rare but expected situations (such as end-of-file).

Indeed, my view is exceptions and exception handling were one of the primary
leaps forward for Ada over its sibling languages Pascal and Modula. Using
exceptions in cases like this allow the writer of the routine to be sure
that the error is not ignored, causing cascading problems later - and ensure
that the error is localized if it is made.

> Exception raising and handling is often viewed as writing code that
> will never execute.  Predefined exceptions must be handled when there
> is an expectation they will be raised, but their usefullness stops
> there.  Beyond that, it's like writing erroneous code on purpose.

Yikes! I hope you never work for me! I think returning an invalid value on
purpose is like writing erroneous code on purpose. That's because you're
trusting the caller to do the right thing and check something; if you look
at the typical C code, it's pretty clear that doesn't happen much.
Exceptions let you put the error recovery code where it makes the most
sense -- which is usually quite a long ways from wherever the error
occurred. And it doesn't require any trust from the user of your
abstraction. (Note that this still applies even when you are your own
consumer - no one is perfect enough to remember to do things not indicated
in the specification.)

                              Randy.





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

* Re: private types
  2006-03-18  2:17           ` Justin Gombos
@ 2006-03-21  0:08             ` Randy Brukardt
  0 siblings, 0 replies; 94+ messages in thread
From: Randy Brukardt @ 2006-03-21  0:08 UTC (permalink / raw)


"Justin Gombos" <rpbkbq.xax.gld@uluv.kbq> wrote in message
news:I4KSf.552$bu.180@trnddc04...
> On 2006-03-18, Randy Brukardt <randy@rrsoftware.com> wrote:
> >
> > Thus, given
> >     A : Positive := 10;
> >     B : Positive;
> > the compiler can assume that A is in range, potentially being able
> > to eliminate checks and speeding up the code. But it cannot assume
> > that B is in range (unless it can prove that it is initialized
> > further on).
> >
> > So I recommend initalizing everything (or assigning it immediately
> > after the begin) that could be significant to performance.
>
> As a rule, I try to put readability ahead of optimizations.  But if I
> did want to write optimum code, I'm not seeing your point here.

You're right about premature optimizations, of course.

> The runtime checks that might be placed on B need not affect code not
> handling B.  Assuming an extreme case, suppose B is not assigned until
> 100 lines later (ie not immediately following the begin).  There
> should be no runtime checks in those 100 lines between the 'begin' and
> the first assignment to B if B is not referenced (and if B is
> referenced prior to assignment, that's a problem that outweighs
> excessive checks anyway).  The first occurrance of B is going to be an
> assignment to B, and it must have the same checks that A would have if
> A were being reassigned at this point.  So I'm not seeing why more
> runtime checks would occur in the case of B.

Because, in general, you don't know whether B is initialized. And Ada 95
requires that invalid values be detected before they cause any damage (with
some unfortunate exceptions). If B is used to index an array, for instance,
it must be checked unless the compiler can prove that it is valid. But that
is very hard in general, because of path issues:

    B : Positive;
 begin
   if Bafflegab (10) then
        B := 10;
   end if;
   ... Str (B) ... -- Must check for invalid values here.
 end;

There is no way that the compiler can tell if B has been initialized or not.
And Ada 95 does not allow *assuming* that it is initialized (which is
essentially what your argument boils down to) -- the compiler must presume
the program is incorrect for this purpose unless it can prove that it is
not.

But note Bob Duff's point that there are other ways to arrange code
generators that might have different effects on checking. That's true in
general, but in this case in particular, the compiler cannot remove the
check for Str (B) no matter what the code generation scheme. If B had been
initialized, it would have been able to in most schemes.

In any case, in most real code, it's hard to prove something is initialized
unless it is done right at the top. Moreover, compilers vary in the amount
of flow analysis that they do. So preinitializtion is the way to go for
maximum portability. (But I suggest this when you're going to initialize the
value anyway, as opposed to initializing it just for this purpose.)

                              Randy.





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

* Re: Uninitialized variables (was: Re: private types)
  2006-03-18  8:39           ` Uninitialized variables (was: Re: private types) Dirk Craeynest
  2006-03-18 14:06             ` Gautier
@ 2006-03-21  0:22             ` Randy Brukardt
  2006-03-21  0:38             ` Randy Brukardt
  2 siblings, 0 replies; 94+ messages in thread
From: Randy Brukardt @ 2006-03-21  0:22 UTC (permalink / raw)



"Dirk Craeynest" <dirk@apollo.cs.kuleuven.ac.be> wrote in message
news:dvgh0s$rtu$1@apollo.cs.kuleuven.ac.be...
> [This thread really is about uninitialized variables now, so I changed
> the subject...]
>
> In article <e_mdncFXrsg5wobZnZ2dnUVZ_t2dnZ2d@megapath.net>,
> Randy Brukardt <randy@rrsoftware.com> wrote:
> >So I recommend initalizing everything (or assigning it immediately
> >after the begin) that could be significant to performance.
>
> We did (and do) feel this is not a good approach, at least not when
> using GNAT or another compiler that supports something like the pragma
> Initialize_Scalars and enhanced validity checking.
>
> For much more about uninitialized variables in Ada code, the following
> paper might be useful:
>
>   "Exposing Uninitialized Variables: Strengthening and Extending
>   Run-Time Checks in Ada" [1],
>   Robert Dewar, Olivier Hainque, Dirk Craeynest, and Philippe
>   Waroquiers,
>   In "Proceedings of the 7th International Conference on Reliable
>   Software Technologies - Ada-Europe 2002" [2], Vienna, Austria,
>   June 17-21, 2002, Johan Blieberger and Alfred Strohmeier (Eds.),
>   volume 2361 of Lecture Notes in Computer Science, pages 193-204,
>   Springer-Verlag, 2002.
>
> The conclusion of that paper contains our recommendation:
>
> ---start-quote---
>
> 5.3 Impact of Usage of Initialize Scalars on How to Program
>
> There is a trend in programming guidelines to "force" initializing
> everything at declaration resulting in code like:
>
>   B : Natural := 0;
>
>   if .... then
>     B := 5;
>   else
>     B := 8;
>   end if;
>
> The difficulty with such an approach is that the initial value is
> meaningless. If this value is used accidentally, the results are
> potentially just as wrong as the use of an uninitialized value, and
> furthermore, the explicit initialization precludes the approach we
> have described in this paper, and thus may introduce bugs that are much
> harder to find and fix. The automatic initialization under control of
> the compiler using Initialize Scalars is a far preferable approach.
>
> We therefore recommend that when a scalar is declared, the programmer
> should avoid initializing it if the code is supposed to set the value
> on all paths.  It is better to let Initialize Scalars + gnatVa detect
> the bug in the code logic rather than trying to deal with meaningless
> initial values. Even for safety-critical programs, we can first compile
> with Initialize Scalars + gnatVa + invalid values and then, if needed,
> field the code with Initialize Scalars + all zero values (if it is the
> case that zero values give the code a better chance of avoiding
> seriously improper behavior).
>
> ---end-quote---
>
> The GNAT manuals provide more information on GNAT's pragma
> Initialize_Scalars [3] and on enhanced validity checking [4].
> Reference [3] mentions:
>
> ---start-quote---
>
> Note that pragma Initialize_Scalars is particularly useful in
> conjunction with the enhanced validity checking that is now provided
> in GNAT, which checks for invalid values under more conditions.
> Using this feature (see description of the -gnatV flag in the users
> guide) in conjunction with pragma Initialize_Scalars provides a
> powerful new tool to assist in the detection of problems caused by
> uninitialized variables.
>
> ---end-quote---
>
> We can assure everyone that from a developers and testers point of view
> the combination of Initialize_Scalars and enhanced validity checking is
> indeed "particularly useful".
>
> References:
> [1] <http://www.cs.kuleuven.be/~dirk/papers/ae02cfmu-paper.pdf>
> [2] <http://www.springer.de/cgi/svcat/search_book.pl?isbn=3-540-43784-3>
> [3]
<http://www.adacore.com/wp-content/files/auto_update/gnat-unw-docs/html/gnat
_rm_2.html#SEC48>
> [4]
<http://www.adacore.com/wp-content/files/auto_update/gnat-unw-docs/html/gnat
_ugn_4.html#SEC47>
>
> Dirk
> Dirk.Craeynest@cs.kuleuven.be (for Ada-Belgium/-Europe/SIGAda/WG9 mail)
>
> *** 11th Intl.Conf.on Reliable Software Technologies - Ada-Europe'2006
> *** June 5-9, 2006 ** Porto, Portugal ** http://www.ada-europe.org ***





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

* Re: Uninitialized variables (was: Re: private types)
  2006-03-18  8:39           ` Uninitialized variables (was: Re: private types) Dirk Craeynest
  2006-03-18 14:06             ` Gautier
  2006-03-21  0:22             ` Uninitialized variables (was: Re: private types) Randy Brukardt
@ 2006-03-21  0:38             ` Randy Brukardt
  2 siblings, 0 replies; 94+ messages in thread
From: Randy Brukardt @ 2006-03-21  0:38 UTC (permalink / raw)


"Dirk Craeynest" <dirk@apollo.cs.kuleuven.ac.be> wrote in message
news:dvgh0s$rtu$1@apollo.cs.kuleuven.ac.be...
> [This thread really is about uninitialized variables now, so I changed
> the subject...]
>
> In article <e_mdncFXrsg5wobZnZ2dnUVZ_t2dnZ2d@megapath.net>,
> Randy Brukardt <randy@rrsoftware.com> wrote:
> >So I recommend initalizing everything (or assigning it immediately
> >after the begin) that could be significant to performance.
>
> We did (and do) feel this is not a good approach, at least not when
> using GNAT or another compiler that supports something like the pragma
> Initialize_Scalars and enhanced validity checking.

(followed by a number of quotes).

I disagree in detail with your conclusions, but probably not in general.

1) Initialize_Scalars is an Annex H thing that is rarely available in Ada
implementations. GNAT is the only one that I know of that has it. I don't
think offering advice that most users can't follow is very helpful.

2) Initialized_Scalars does no good when you have full range types (which
are very common in a compiler, for instance). In that case, it is equivalent
to initializing to a random value, and worse, it gives a false sense of
security.

3) "The initial value is meaningless". Here I agree and disagree with you.
The agreement is that you shouldn't initialize to a meaningless value. The
disagreement is that for most variables, there is an obvious initial value
(like Null for access types) that is not meaningless. For instance, I have a
lot of string processing code in the spam filter that have length variables.
I usually initialize the length to zero (empty), because that *is* the
initial state of the object. So, much of time there is a useful
initialization.

It think it is better to *avoid* uninitialized variables than to argue about
how to *handle* uninitialized values. The example you gave:

  B : Natural := 0;
  if .... then
    B := 5;
  else
    B := 8;
  end if;

is awful, I agree. But I'd probably write:

  B : Natural := 8;
  if .... then
    B := 5;
  -- else use the default values
  end if;

instead, and the initial value is no longer meaningless. Similarly, I use a
lot of blocks, and try to keep the declarations on variables to scopes where
their initial values are known (or immediately initialized). Both of these
are better than *any* technique to handle uninitialized variables.

4) As your note suggested, assuming that everything is tested is dangerous.
It's necessary in the fielded system to protect against uninitialized
variables causing weird results. I just prefer to do it from the beginning
(by reducing them as much as possible). And I'd prefer to rely on
compile-time warnings (which GNAT also does well, BTW) to get rid of them at
the source.

5) Any extra cost from initializing objects to meaningful values early (and
such cost is usually quite small) will quickly pay for itself. (I think that
is in line with the conclusions of the paper, too).

Conclusion: don't write uninitialized variables in the first place; but use
your head to eliminate them - junk initializations are no better than the
uninitialized variables that they replace. Mindless following of coding
standards always produces junky code.

                                          Randy.





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

* Re: private types
  2006-03-20 19:12                         ` Martin Krischik
@ 2006-03-21  7:27                           ` Maciej Sobczak
  0 siblings, 0 replies; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-21  7:27 UTC (permalink / raw)


Martin Krischik wrote:

>>NULL is not depreciated. It's defined in the <cstddef> header to be a
>>null-pointer constant, which is any integral const expression that
>>evaluates to 0. Possible definition is:
> 
> But that is only a C compatibility header

No, there is nothing like this in C++. The C library is part of C++ by 
explicit inclusion, not by compatibility.
Consider, for example, general purpose functions, like rand() (this one 
declared in <cstdlib>). It does not make any sense to say that such 
functions are C-compatibility stuff only, because that would imply that 
it's not possible to do even such basic things in "pure" C++.

C++ *contains* the C library. It uses different header names (for 
example, cstdlib instead of stdlib.h) and namespace std (so that you 
have std::rand, std::printf, etc.), but everything is there and 
everything is part of C++. Including NULL.


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: private types
  2006-03-20 19:32                         ` Martin Krischik
@ 2006-03-21  7:41                           ` Maciej Sobczak
  0 siblings, 0 replies; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-21  7:41 UTC (permalink / raw)


Martin Krischik wrote:

>>The interesting question is why it might make any difference to you?
>>The only thing that really matters is that the null pointer is distinct
>>from any other valid pointer, in which case it's equivalent to Ada's
>>null.
> 
> For C++ I can - barely - see that but C is supposed to system programming
> language suitable for kernel and/or embedded progamming. Taking that into
> account: How actually are the languages implementers to implement 
> "distinct from any other valid pointer".

Any way they want.

> If you are implementing a Ring 0
> device driver on x86 all pointers are valid and on PC architecture there is
> memory at (void*0) which one might want to access.

The point is that if you are writing software for some specific piece of 
hardware, then handling of NULL is the least of your problems. You need 
extensive knowledge and guarantees, considering, among others, stuff 
like word sizes, alignment, byte ordering, representation and existence 
of trap values, etc. In other words, you don't just pick any compiler at 
random, but rather you use the one which gives you the set of required 
guarantees. And among those guarantees there will be something about the 
NULL pointer.
Most likely you will just know that the NULL pointer has representation 
of all bits zero.

Note also that in so called reality compilers that do not implement NULL 
as zero just do not sell very well. This is because many C programmers 
are used to do this:

struct S
{
     int x;
     char *p;
     /* ... */
};

struct S s;
memset(&s, 0, sizeof(S));  /* <- here */

and later expect that s.p == NULL;

The "idiom" of memsetting structures is so deeply rooted in the C 
community that you can find it in almost every C program and most C 
books. It's clear that the "idiom" bypasses the typesafety of fields by 
just plowing over their underlying representation, and this can work 
only with those compilers that do not exercise the full freedom that the 
standard gives them.

So - no worry. It just works. :)


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: private types
  2006-03-20 15:09                       ` Robert A Duff
@ 2006-03-21  8:07                         ` Maciej Sobczak
  2006-03-26 18:53                           ` Robert A Duff
  0 siblings, 1 reply; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-21  8:07 UTC (permalink / raw)


Robert A Duff wrote:

>>>Only a very few C/C++ programmers
>>>actually master the language.
>>
>>As is true for any language that is at least moderately useful.
> 
> True.  Language designers ought to take that into account -- whenever
> possible, try to design features subtle misunderstandings are unlikely
> to cause bugs.

True, I don't have any doubts about it.

> Suppose an Ada programmer and a C++ programmer both think that null/NULL
> must be represented as all-zero-bits.  Both programmers are confused.

Both programmers take assumptions which are equally wrong.

> But which programmer is more likely to write code that won't work
> on a machine where the assumption turns out to be false?

Naither of those programmer should have any problems with their 
programs, because pointers are, well, pointers, not integers. Neither of 
them should have any temptation to interpret pointers as numbers, so 
that the actual "value" of the pointer never really matters. Even the 
question "is the NULL pointer zero?" makes no sense in this light, 
unless you target specific piece of silicon (see my replies to Martin 
Krischik).

In practice, in the world of pointers it's not the NULL pointer 
representation which is causing problems, but rather unconstrained 
pointer arithmetics.

-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: Handling invalid objects
  2006-03-20 23:44               ` Randy Brukardt
@ 2006-03-22  1:27                 ` Justin Gombos
  0 siblings, 0 replies; 94+ messages in thread
From: Justin Gombos @ 2006-03-22  1:27 UTC (permalink / raw)


On 2006-03-20, Randy Brukardt <randy@rrsoftware.com> wrote:
>
>> The quality and style guide advises against them for a good reason;
>> exceptions are like gotos - and produce a questionable state.
>
> The state isn't questionable in this case: you have no legitimate
> value to return, so anything you return is garbage. That means there
> isn't any state to corrupt.

I didn't post an sample body for function hour_of_day return
clock_type, so you don't have enough information to be able to
conclude whether the state is corrupted.  For all we know, hour_of_day
is impure and modifies global data, and raises exceptions from
multiple points.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: Handling invalid objects
  2006-03-20 23:57                   ` Randy Brukardt
@ 2006-03-22  2:06                     ` Justin Gombos
  2006-03-22  5:23                       ` tmoran
  0 siblings, 1 reply; 94+ messages in thread
From: Justin Gombos @ 2006-03-22  2:06 UTC (permalink / raw)


On 2006-03-20, Randy Brukardt <randy@rrsoftware.com> wrote:
>
> You should have; such a coding standard is brain-damaged. Unless
> there is a total ban on exceptions (as in SPARK -- and I disagree
> with SPARK on that), there is no good reason to avoid
> exceptions. 

You would avoid exceptions for the same reasons you might avoid using
a goto statement.  An exception is only a specific type of goto
statement - and gotos are not exactly state of the art.

> Indeed, my view is exceptions and exception handling were one of the
> primary leaps forward for Ada over its sibling languages Pascal and
> Modula. Using exceptions in cases like this allow the writer of the
> routine to be sure that the error is not ignored, causing cascading
> problems later - and ensure that the error is localized if it is
> made.

Quite the opposit.  I see neglected potentially raisable exceptions
routinely.  They are particularly easy to ignore - and in fact often
difficult for untrained users to even know they're using something
that would raise an exception.  This makes exceptions the worst kind
of goto.  You can command a jump without even providing a place to go.

It is the alternatives that forces the user of an API to address
problem cases.  In the case of functions, wrapping return data in a
varient record is not something that can be ignored.  Ignoring an
"out" object on a procedure requires cases of neglect to be
deliberate.

>> Exception raising and handling is often viewed as writing code that
>> will never execute.  Predefined exceptions must be handled when
>> there is an expectation they will be raised, but their usefullness
>> stops there.  Beyond that, it's like writing erroneous code on
>> purpose.
>
> Yikes! I hope you never work for me! 

Rightly so.  Bringing me into a sloppy environment with undisciplined
Ada programmers and a mess of spaghetti code could quickly create a
tough environment - and a particularly hostile one if I'm also forced
to do poor quality work myself.  I would not be a team player in that
case, and you should not hire me.  

> I think returning an invalid value on purpose is like writing
> erroneous code on purpose. That's because you're trusting the caller
> to do the right thing and check something; 

It's exceptions that require trust.  In fact, you can ignore an
exception accidentally.  Return a known and documented bad value, or
varient record, and the user must not incompetent to miss it.

Well developed Adaists can pull off using exceptions conservatively
(just like they can gotos), with minimal benefit.  However, you also
can't ignore the fact that most Ada developers are incompetent, and
will write code that doesn't execute, create exceptions for situations
that are not exceptional, and fail to handle exceptions.  I've seen
new developers use exceptions to handle normal operating conditions.
And you can't get away with only letting the advanced users write
exceptions, because their code will interface with that of a
non-proficient programmer.  There are too many gotchas to justify them
in light of better alternatives.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: Handling invalid objects
  2006-03-22  2:06                     ` Justin Gombos
@ 2006-03-22  5:23                       ` tmoran
  2006-03-22  8:48                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 94+ messages in thread
From: tmoran @ 2006-03-22  5:23 UTC (permalink / raw)


>  An exception is only a specific type of goto
>  statement - and gotos are not exactly state of the art.
  If it doesn't quack, doesn't waddle, and doesn't look like a duck,
it's not a duck.  An exception both looks and acts quite different
from a goto.



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

* Re: Handling invalid objects
  2006-03-22  5:23                       ` tmoran
@ 2006-03-22  8:48                         ` Dmitry A. Kazakov
  2006-03-22  9:24                           ` Maciej Sobczak
  0 siblings, 1 reply; 94+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-22  8:48 UTC (permalink / raw)


On Tue, 21 Mar 2006 23:23:10 -0600, tmoran@acm.org wrote:

>>  An exception is only a specific type of goto
>>  statement - and gotos are not exactly state of the art.
>   If it doesn't quack, doesn't waddle, and doesn't look like a duck,
> it's not a duck.  An exception both looks and acts quite different
> from a goto.

If exceptions are gotos, then return codes should be gotos with label
variables! (:-))

Still exception contracts would greatly improve safety of Ada as a
language.

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



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

* Re: Handling invalid objects
  2006-03-22  8:48                         ` Dmitry A. Kazakov
@ 2006-03-22  9:24                           ` Maciej Sobczak
  2006-03-22 11:05                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-22  9:24 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> Still exception contracts would greatly improve safety of Ada as a
> language.

If by exception contracts you mean embedding the exception specification 
in the "signature" of the procedure/function, then it was already 
exercised by the Java community with rather disappointing effects.


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: Handling invalid objects
  2006-03-22  9:24                           ` Maciej Sobczak
@ 2006-03-22 11:05                             ` Dmitry A. Kazakov
  2006-03-22 16:42                               ` Maciej Sobczak
  0 siblings, 1 reply; 94+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-22 11:05 UTC (permalink / raw)


On Wed, 22 Mar 2006 10:24:10 +0100, Maciej Sobczak wrote:

> Dmitry A. Kazakov wrote:
> 
>> Still exception contracts would greatly improve safety of Ada as a
>> language.
> 
> If by exception contracts you mean embedding the exception specification 
> in the "signature" of the procedure/function, then it was already 
> exercised by the Java community with rather disappointing effects.

If Java did it wrong, let's do it right in Ada.

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



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

* Re: Handling invalid objects
  2006-03-22 11:05                             ` Dmitry A. Kazakov
@ 2006-03-22 16:42                               ` Maciej Sobczak
  2006-03-22 18:06                                 ` Stefan Lucks
  2006-03-23 13:20                                 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 94+ messages in thread
From: Maciej Sobczak @ 2006-03-22 16:42 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

>>If by exception contracts you mean embedding the exception specification 
>>in the "signature" of the procedure/function, then it was already 
>>exercised by the Java community with rather disappointing effects.
> 
> If Java did it wrong, let's do it right in Ada.

Do what exactly? This is important question.
The problem with exception specifications is that they are 
self-contradictory:

- We use exceptions when we want to *DECOUPLE* error reporting from 
error handling. We find it especially good in those situations, where 
error reporting site and error handling site are separated by more than 
one level of subroutine calls (otherwise returning error codes is good 
enough).

- We embed contract information in subroutine signatures to *COUPLE* the 
caller with the callee with respect to what they provide to each other 
and what they expect from each other.

Now, "coupling" and "decoupling" are hardly compatible. Let's see where 
it breaks in so-called practice.

First, there is a cascading effect when someone on one end of the chain 
adds a new exception type. Just let's say that the project evolved and 
for example a database got involved in something that was previously 
managed with the use of files. There is a new DBError exception, 
possibly having some db-specific information encoded (you know, 
exceptions are real objects in some languages :) ). This error is not 
handled neither by the offending function nor anybody in the chain, but 
is supposed to be handled at some higher level. In this scheme, the poor 
programmer has to add the DBError type to the exception specification to 
*all* functions in the chain. And apart from being a maintenance horror, 
it might be just impossible because the functions on the road are 
already closed or just owned by someone else.
The tempting "solution" is to shut up the exception to meet the 
specification which was already cast in stone. Just grep any bigger Java 
project for things like:

catch (Throwable e) {} // <- empty block here!

to see it at work.

Java guys can at least try to fight this problem with inheritance. The 
exception need not be exactly of the specified type, but might be 
something derived from what was specified. So, the other temptation is 
to specify the exception type that is rather general (higher in the 
inheritance hierarchy) to ease the accommodation of new exception types. 
But the more general is the specification, the less useful it is with 
regard to enforcing anything. In the extreme, it does not enforce 
anything at all.

(Note that Ada would not have this possibility, or it would need to 
allow for exception hierarchies.)

Second, the problem is that the error reporting and handling might be 
stated as a contract not between immediate caller and callee, but 
between some entities that operate across some other entity. A C++ 
example could be:

void myFun()
{
     vector<MyType> array;
     // ...
     sort(array.begin(), array.end(), myComparator());
     // ...
}

Above, the call chain is myFun->sort->myComparator, but the error 
handling and reporting is the business which is agreed between myFun and 
myComparator only. The sort algorithm was written long before myFun and 
myComparator and it (sort) does not care what it sorts and for whom. 
This means that sort should be completely transparent to the agreement 
that myFun and myComparator might have with regard to error reporting 
and handling.

The solution might be to allow the compiler to synthesise the exception 
specs for sort automatically. But then, the specs would be just useless, 
because it would not enforce anything.

The real problem is that languages based on simple subroutine calls are 
not appropriate for expressing these kind of relationships. Something 
fundamentally different would be needed to ensure that myFun handles 
exceptions from myComparator without involving sort in this process, but 
I don't see what that thing would look like.

Anyway. The whole purpose of exceptions is to provide a kind of 
"out-of-band" channel which is *decoupled* from the main chain of 
subroutine calls. This "out-of-band" property is something that you 
either like (and/or accept) or not in the given project. Messing around 
with things like exception specifications is just swimming upstream - 
you cannot provide coupling into something that was *intended* to be 
"out-of-band" in the first place.

Java guys failed with this exercise. C++ community dropped the idea 
altogether before failing (C++ never had compile-time enforcements of 
exceptions specs and today nobody's using them anyway). I don't see how 
Ada would do something like this without incurring effects described 
above or without fundamentally changing something in the way subroutines 
are used. But I'm looking forward to see your opinions on this (and 
maybe learn something about Ada culture? :) ).


-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/



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

* Re: Handling invalid objects
  2006-03-22 16:42                               ` Maciej Sobczak
@ 2006-03-22 18:06                                 ` Stefan Lucks
  2006-03-23 13:20                                 ` Dmitry A. Kazakov
  1 sibling, 0 replies; 94+ messages in thread
From: Stefan Lucks @ 2006-03-22 18:06 UTC (permalink / raw)


On Wed, 22 Mar 2006, Maciej Sobczak wrote:

> Dmitry A. Kazakov wrote:
>
> > If Java did it wrong, let's do it right in Ada.
>
> Do what exactly? This is important question.
> The problem with exception specifications is that they are
> self-contradictory:
>
> - We use exceptions when we want to *DECOUPLE* error reporting from
> error handling. We find it especially good in those situations, where
> error reporting site and error handling site are separated by more than
> one level of subroutine calls (otherwise returning error codes is good
> enough).
>
> - We embed contract information in subroutine signatures to *COUPLE* the
> caller with the callee with respect to what they provide to each other
> and what they expect from each other.
>
> Now, "coupling" and "decoupling" are hardly compatible.

[...]
> Ada would do something like this without incurring effects described
> above or without fundamentally changing something in the way subroutines
> are used. But I'm looking forward to see your opinions on this (and
> maybe learn something about Ada culture? :) ).

One thing Ada could reasonably do is to *enable* subroutines to *promise*
to raise no exceptions, or only certain exceptions. (And, of course, to
enable the compiler to verify if this promise is kept. This would, be a
little bit similar to SPARK, which can prove the exception-freedom of
subroutines.)

Of couse, the implication is that the subroutine itself may only use (or
rather "with" ;-) subroutines which make a similar promise, or have to
handle all exceptions ("others").

As an example for a notation, sonsider the following subroutines which any
freedom to raise and propagate exceptions deliberately:

   function "+"(A, B: T) return T;
   procedure Get (Item: out T);
   procedure Put (Item: T);

The remaining source code is not Ada. (Or perhaps it is Ada 2015? :-)

No Exceptions raised:

   function "+"(A, B: T) return T
     raise null;
   procedure Get (Item: out T)
     raise null;
   procedure Put (Item: T)
     raise null;

Some Exceptions may be raised:

   function "+"(A, B: T) return T
     raise Constraint_Error, Program_Error;
        -- can raise or propagate Program_Error, but nothing else

   procedure Get (Item: out T)
     raise Ada.Text_IO.End_Error,
           Ada.Text_IO.Data_Error,
           Ada.Text_IO.Mode_Error,
           Ada.Text_IO.Layout_Error;
        -- can raise or propagate these four exception, none else

   Line_Failed : exception;

   procedure PutLine (Item: T)
     raise Ada.Text_IO.End_Error,
           Ada.Text_IO.Data_Error,
	   Line_Failed;
        -- can raise or propagate these three exceptions none else

   procedure Put (Item: T)
     raise Ada.Text_IO.End_Error,
           Ada.Text_IO.Data_Error,
	   package;
        -- can raise or propagate two exceptions from Ada.Text_IO
        -- and any exception defined in the current package

I could also imagine a package to specify which errors might be raised or
propagated in any of its subroutines. This would simplify notation.
Consider the following almost-complete example for a package specification

with Ada.Text_IO;

package Some_Library
  raise
     Ada.Text_IO.End_Error, Ada.Text_IO.Data_Error,
     Ada.Text_IO.Mode_Error, Ada.Text_IO.Layout_Error,
     Constrained_Error, Program_Error,
     package;

   -- Any subroutine defined here may raise the four exceptons from
   -- Ada.Text_IO, the two exceptions Constrained_Error, Program_Error,
   -- from Standard, and the exception(s) defined in the package, namely
   -- Line_Failed.

   Line_Failed : exception;

   type T is private;

   function "+"(A, B: T) return T;
   procedure PutLine (Item: T);
   procedure Put (Item: T);

private
   type T is ...; -- which type T wold you like?

end Mod_Some;


Further, when a subroutines X formal parameter is access-to-subroutine,
then any exception raised by a subroutine given as an actual parameter
need not be handled by X. This should be the caller's duty.


-- 
Stefan Lucks      Th. Informatik, Univ. Mannheim, 68131 Mannheim, Germany
            e-mail: lucks@th.informatik.uni-mannheim.de
            home: http://th.informatik.uni-mannheim.de/people/lucks/
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Handling invalid objects
  2006-03-22 16:42                               ` Maciej Sobczak
  2006-03-22 18:06                                 ` Stefan Lucks
@ 2006-03-23 13:20                                 ` Dmitry A. Kazakov
  1 sibling, 0 replies; 94+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-23 13:20 UTC (permalink / raw)


On Wed, 22 Mar 2006 17:42:53 +0100, Maciej Sobczak wrote:

> Dmitry A. Kazakov wrote:
> 
>>>If by exception contracts you mean embedding the exception specification 
>>>in the "signature" of the procedure/function, then it was already 
>>>exercised by the Java community with rather disappointing effects.
>> 
>> If Java did it wrong, let's do it right in Ada.
> 
> Do what exactly? This is important question.

Sure.

> - We use exceptions when we want to *DECOUPLE* error reporting from 
> error handling. We find it especially good in those situations, where 
> error reporting site and error handling site are separated by more than 
> one level of subroutine calls (otherwise returning error codes is good 
> enough).

Yes, though also see below.

> - We embed contract information in subroutine signatures to *COUPLE* the 
> caller with the callee with respect to what they provide to each other 
> and what they expect from each other.

No, we are decoupling using contracts. Instead of presenting any concrete 
caller, we do a contract. The callee is coupled only to its contract. It 
does not to any caller, because it hopes that any caller will respect the 
contract.

> Now, "coupling" and "decoupling" are hardly compatible. Let's see where 
> it breaks in so-called practice.
>
> First, there is a cascading effect when someone on one end of the chain 
> adds a new exception type. Just let's say that the project evolved and 
> for example a database got involved in something that was previously 
> managed with the use of files.

This is not specific to exceptions. It is "fragile class" design.

You cannot add a new exception type [better to say a class of], this breaks 
the contract. You have to stay within the class.

In Ada model, where exceptions are values, this means that the exception 
contracts should specify ranges of values [subtype] and a new exception 
[value] should be chosen from that range. It is doable.

> Second, the problem is that the error reporting and handling might be 
> stated as a contract not between immediate caller and callee, but 
> between some entities that operate across some other entity.
[...]
> The real problem is that languages based on simple subroutine calls are 
> not appropriate for expressing these kind of relationships. Something 
> fundamentally different would be needed to ensure that myFun handles 
> exceptions from myComparator without involving sort in this process, but 
> I don't see what that thing would look like.

I think it was Robert Duff, who proposed a nice solution for this. When you 
have some procedure composed out of another procedure, in this example, you 
pass it as a parameter, you could say something like:

   A raises this plus anything what B does.

Because B has a defined subroutine type, its contract is statically known.

One could also bind exceptions to types of primitive subprograms. For 
example:

   type File is tagged ...;
   subtype File_Error is File'Exception;
      -- The range of exceptions bound to File
   procedure Read (X : File) exception File_Error;

   type DB is new File with ...;
   DB_Error : File_Error := some sugar;
      -- Declares a new exception in the range
   procedure Read (X : DB); -- This is allowed to raise DB_Error

> Anyway. The whole purpose of exceptions is to provide a kind of 
> "out-of-band" channel which is *decoupled* from the main chain of 
> subroutine calls.

This is a control-flow view. But there is another, more general view. 
Exceptions allow us to weaken preconditions. Without exceptions, a 
real-valued sqrt should specify x >= 0.0 as a precondition. This is 
unacceptable when x is statically unknown. Exceptions relax the 
precondition and bring things back to static. The price is that you leave 
the realm of real numbers. You have to this way or another. Either you make 
it complex-valued or you say that the result is "Real or Constraint_Error." 
Who will deal with this result is the question for another day. But when 
exceptions are not contracted, then the gain of static preconditions gets 
lost. So in my view, Java's is undoubtedly right here.

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



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

* Re: private types
  2006-03-18 15:06             ` Justin Gombos
  2006-03-19  9:35               ` Martin Krischik
@ 2006-03-25 21:40               ` Robert A Duff
  2006-03-26  0:10                 ` Justin Gombos
  2006-03-26  3:15                 ` Frank J. Lhota
  1 sibling, 2 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-25 21:40 UTC (permalink / raw)


Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

> On 2006-03-18, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
> >
> > In Ada, if an object of an access type has no explicit initial
> > value, you can't easily tell whether that means "null is a
> > meaningful value for this variable, and that's the default I want"
> > versus "this variable will be initialized to a meaningful (non-null)
> > value later".
> 
> If you want to distinguish between the two possiblities, you could
> explicitly initialize your pointers to null in the first case, and not
> in the second.

Yes, that's a reasonable style, and I use it myself.
But there's no compiler support for that style.
As far as the language and compiler are concerned,
"X: T" and "X: T := null" mean EXACTLY the same thing.
It's hard to tell whether the programmer means the same thing
in these cases.

>...  I rarely use access types,

So you rarely create trees, linked list, etc?

>... and I probably wouldn't do
> that myself simply because I find the distinction unimportant for
> access types.  Regardless, I'm not going to give up the benefit of
> having this distinction on non-access scalars simply because my access
> type declarations don't have it.
> 
> > This is exactly analogous to the case with integers -- if they were
> > default-initialized to zero, you can't easily tell whether zero is
> > intended as a meaningful initial value, versus later initialization
> > to a meaningful value.
> 
> Integers, and other non-access scalars are different in this case
> because you cannot expect zero to have the same meaning.  Zero has a
> universal meaning with access types,

No, zero has no meaning with access types!

>... but it could be in range or out
> of range for any other type.  The ARM selects access types
> specifically to get a default initialization of zero for this reason.

There is no "default initialization of zero".  There is a default-init
to null, which has nothing to do with zero (according to the Ada
standard).

- Bob



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

* Re: private types
  2006-03-25 21:40               ` Robert A Duff
@ 2006-03-26  0:10                 ` Justin Gombos
  2006-03-26  1:00                   ` Robert A Duff
  2006-03-26  3:15                 ` Frank J. Lhota
  1 sibling, 1 reply; 94+ messages in thread
From: Justin Gombos @ 2006-03-26  0:10 UTC (permalink / raw)


On 2006-03-25, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
> Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:
>
> So you rarely create trees, linked list, etc?

That's right.  In fact, a few months ago was the first time I
implemented a dynamic container in Ada since I studied it in school.
I haven't had a need for them in any of the avionics systems that I've
worked.

>> Integers, and other non-access scalars are different in this case
>> because you cannot expect zero to have the same meaning.  Zero has
>> a universal meaning with access types,
>
> No, zero has no meaning with access types!
>
>>... but it could be in range or out of range for any other type.
>>The ARM selects access types specifically to get a default
>>initialization of zero for this reason.
>
> There is no "default initialization of zero".  There is a
> default-init to null, which has nothing to do with zero (according
> to the Ada standard).

You're forgetting why we got side tracked on this discussion.  Your
comment was:

  I'm not sure what the right answer is, but surely all the arguments
  for and against dummy values apply equally to access types.

Access types are special, and get different treatment than other
scalars because they include in their set a representation for a null
value.  Integers do not; so the same arguements for implicit
initialization of access values do not necessarily apply.  

Whether null values are actually represented as zeros is irrelevant to
this matter.  Even if null values are nonzero, integers still do not
have a null object.

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-26  0:10                 ` Justin Gombos
@ 2006-03-26  1:00                   ` Robert A Duff
  2006-03-26  6:37                     ` Jeffrey R. Carter
  0 siblings, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-26  1:00 UTC (permalink / raw)


Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

> On 2006-03-25, Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
> > Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:
> >
> > So you rarely create trees, linked list, etc?
> 
> That's right.  In fact, a few months ago was the first time I
> implemented a dynamic container in Ada since I studied it in school.
> I haven't had a need for them in any of the avionics systems that I've
> worked.

OK.  I'm a compiler writer, so I use pointers (access types or whatever)
quite a lot.

> >> Integers, and other non-access scalars are different in this case
> >> because you cannot expect zero to have the same meaning.  Zero has
> >> a universal meaning with access types,
> >
> > No, zero has no meaning with access types!
> >
> >>... but it could be in range or out of range for any other type.
> >>The ARM selects access types specifically to get a default
> >>initialization of zero for this reason.
> >
> > There is no "default initialization of zero".  There is a
> > default-init to null, which has nothing to do with zero (according
> > to the Ada standard).
> 
> You're forgetting why we got side tracked on this discussion.

Sorry.  These discussions tend to ramble a bit.  ;-)

>...Your
> comment was:
> 
>   I'm not sure what the right answer is, but surely all the arguments
>   for and against dummy values apply equally to access types.

And I stand by that comment.

> Access types are special, and get different treatment than other
> scalars because they include in their set a representation for a null
> value.

Yes, access types in Ada are special, because they have a special null
value.  C and Pascal and so forth are similar.  But it doesn't HAVE to
be that way.  Some languages (SML comes to mind) do not have a special
null value provided for free -- if you want one, you declare one.
(Or, if you want two, you declare two!)

>...Integers do not; so the same arguements for implicit
> initialization of access values do not necessarily apply.

Again, it doesn't have to be that way.  The language designer could
provide a special value for integers, too.

Most of the time, I do not want a special null value (neither for access
types nor for integers).  I would prefer a language that did not give me
special null values for free -- they're just a tripping hazard, except
when I want them.

The Ada 2005 "not null" thing is somewhat helpful, in this regard.

> Whether null values are actually represented as zeros is irrelevant to
> this matter.

Quite true.  Sorry -- I was confused by your referring to zero as a null
access value.

- Bob



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

* Re: private types
  2006-03-25 21:40               ` Robert A Duff
  2006-03-26  0:10                 ` Justin Gombos
@ 2006-03-26  3:15                 ` Frank J. Lhota
  2006-03-26 18:28                   ` Robert A Duff
  1 sibling, 1 reply; 94+ messages in thread
From: Frank J. Lhota @ 2006-03-26  3:15 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message 
news:wccr74q19up.fsf@shell01.TheWorld.com...
>>...  I rarely use access types,
>
> So you rarely create trees, linked list, etc?

Not necessarily; One could create these entities using a container library 
such as the Booch components or the 2005 Ada Containers. Of course, such 
libraries will use acess types in their implementation, but the end user 
does not have to handle access values directly.

-- 
"All things extant in this world,
Gods of Heaven, gods of Earth,
Let everything be as it should be;
Thus shall it be!"
- Magical chant from "Magical Shopping Arcade Abenobashi"

"Drizzle, Drazzle, Drozzle, Drome,
Time for this one to come home!"
- Mr. Lizard from "Tooter Turtle"





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

* Re: private types
  2006-03-26  1:00                   ` Robert A Duff
@ 2006-03-26  6:37                     ` Jeffrey R. Carter
  2006-03-26 15:43                       ` Justin Gombos
  2006-03-26 16:51                       ` Robert A Duff
  0 siblings, 2 replies; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-26  6:37 UTC (permalink / raw)


Robert A Duff wrote:
> Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:
>> Access types are special, and get different treatment than other
>> scalars because they include in their set a representation for a null
>> value.
> 
> Yes, access types in Ada are special, because they have a special null
> value.  C and Pascal and so forth are similar.  But it doesn't HAVE to
> be that way.  Some languages (SML comes to mind) do not have a special
> null value provided for free -- if you want one, you declare one.
> (Or, if you want two, you declare two!)

I think we're missing the point. Access types are NOT scalar types in Ada. C 
pointers may be, since you can treat them pretty much like integers. The ARM TOC has

3.5 Scalar Types
3.5.1 Enumeration Types
3.5.2 Character Types
3.5.3 Boolean Types
3.5.4 Integer Types
3.5.5 Operations of Discrete Types
3.5.6 Real Types
3.5.7 Floating Point Types
3.5.8 Operations of Floating Point Types
3.5.9 Fixed Point Types
3.5.10 Operations of Fixed Point Types

and

3.10 Access Types
3.10.1 Incomplete Type Declarations
3.10.2 Operations of Access Types

Access types are NOT in the section for scalar types (3.5); they are in their 
own, separate section (3.10). Once you accept that access types are not scalar 
types, arguing about the meaning of null changes. Access types are an 
abstraction, and the concept of null is part of that abstraction. In the 
abstraction, an access value either designates an object or it doesn't; = null 
means the former and /= null, the latter. How that is represented is an 
implementation detail hidden from the user. You could have something sort of 
equivalent to

    type Access_Type is private;

    null : constant Access_Type;
private
    type Access_Type (Designates_Something : Boolean := False) is record
       case Designates_Something is
       when False =>
          null;
       when True =>
          Data : System.Address;
          -- other fields as needed
       end case;
    end record;

    null : constant Access_Value := (Designates_Something => False);

(though I doubt any compiler actually does). Access types aren't special 
compared to scalar types because they're not scalar types; they're not even 
conceptually similar.

-- 
Jeff Carter
"I spun around, and there I was, face to face with a
six-year-old kid. Well, I just threw my guns down and
walked away. Little bastard shot me in the ass."
Blazing Saddles
40



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

* Re: private types
  2006-03-26  6:37                     ` Jeffrey R. Carter
@ 2006-03-26 15:43                       ` Justin Gombos
  2006-03-26 16:32                         ` Robert A Duff
  2006-03-26 16:51                       ` Robert A Duff
  1 sibling, 1 reply; 94+ messages in thread
From: Justin Gombos @ 2006-03-26 15:43 UTC (permalink / raw)


On 2006-03-26, Jeffrey R. Carter <spam.not.jrcarter@acm.not.spam.org> wrote:
>
> I think we're missing the point. Access types are NOT scalar types
> in Ada. C pointers may be, since you can treat them pretty much like
> integers. 

I believe you're right.  I had the idea that access types are scalars
from page 18 of Michael Feldman's book "Software Construction and Data
Structures with Ada 95," but apparently he's wrong about that.

> Access types aren't special compared to scalar types because they're
> not scalar types; they're not even conceptually similar.

Exactly, so it's reasonable to treat access types differently when it
comes to default initialization, despite Robert Duffs comment that the
arguments for/against apply to both kinds of types.  After reading
Duff's last post, I can see that he was talking outside of the
language, so that's where the misunderstanding was.  My position had a
premise that we're dealing with Ada integers as they are (that is,
non-abstract, and without a null value).

-- 
PM instructions: do a C4esar Ciph3r on my address; retain punctuation.



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

* Re: private types
  2006-03-26 15:43                       ` Justin Gombos
@ 2006-03-26 16:32                         ` Robert A Duff
  0 siblings, 0 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-26 16:32 UTC (permalink / raw)


Justin Gombos <rpbkbq.xax.gld@uluv.kbq> writes:

>...After reading
> Duff's last post, I can see that he was talking outside of the
> language, ...

Yes, of course!  We were talking about how Ada _ought_ to deal with
uninitialized variables.  Therefore, we must be talking about
hypothetical languages that are different from Ada.

>...so that's where the misunderstanding was.  My position had a
> premise that we're dealing with Ada integers as they are (that is,
> non-abstract, and without a null value).

Yes, access types have null, and integers do not (in Ada).
But that's not a good argument that access types _should_
have null, or that integers should _not_ have null.
"It's best if Ada does X, because Ada does X" -- that's
circular reasoning.  ;-)

- Bob



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

* Re: private types
  2006-03-26  6:37                     ` Jeffrey R. Carter
  2006-03-26 15:43                       ` Justin Gombos
@ 2006-03-26 16:51                       ` Robert A Duff
  2006-03-26 19:41                         ` Jeffrey R. Carter
  1 sibling, 1 reply; 94+ messages in thread
From: Robert A Duff @ 2006-03-26 16:51 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.not.jrcarter@acm.not.spam.org> writes:

> Access types are NOT in the section for scalar types (3.5); they are in
> their own, separate section (3.10). Once you accept that access types
> are not scalar types,...

Sorry, but I don't "get" this argument.

I accept that access types are not scalar types.  Both are "elementary"
types, however.  I don't see any fundamental difference between access
and scalar that would imply that uninit vars should be treated
differently for the two.

Of course, there are many fundamental differences, which imply a
different set of operations (can't do arithmetic on access values,
can't do 'Access and get an integer, etc).  But there are also
many things in commmon between scalar and access: both can be passed
as parameters, both can be stored as record components, both are by-copy
types.

An uninit var should be considered a bug, whether it's access or
integer.  I see no fundamental difference, here.  Defaulting to null
hides this bug.

>... arguing about the meaning of null changes. Access
> types are an abstraction, and the concept of null is part of that
> abstraction. In the abstraction, an access value either designates an
> object or it doesn't; = null means the former and /= null, the
> latter.

Yes, but my claim is that that's a poorly designed abstraction.
In most cases, null is just a tripping hazard.
The programmer should have the choice -- access type without
any special value, access type with a special value that doesn't
designate anything, access type with _two_ special values, ...

Ada 2005 comes closer, by having "not null" -- but the default is
backwards (for obvious compatibility reasons).

Note that when I declare a private type, I choose whether it should have
"special" values, and what they mean.  And I choose whether a special
value is used as a default.  I can choose to raise an exception if
clients look at an uninit var.  I can choose to prevent uninit
vars statically, using (<>) discriminants.

- Bob



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

* Re: private types
  2006-03-26  3:15                 ` Frank J. Lhota
@ 2006-03-26 18:28                   ` Robert A Duff
  2006-03-26 19:43                     ` Jeffrey R. Carter
  2006-03-26 19:59                     ` Simon Wright
  0 siblings, 2 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-26 18:28 UTC (permalink / raw)


"Frank J. Lhota" <NOSPAM.FrankLho@rcn.com> writes:

> "Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message 
> news:wccr74q19up.fsf@shell01.TheWorld.com...
> >>...  I rarely use access types,
> >
> > So you rarely create trees, linked list, etc?
> 
> Not necessarily; One could create these entities using a container library 
> such as the Booch components or the 2005 Ada Containers. Of course, such 
> libraries will use acess types in their implementation, but the end user 
> does not have to handle access values directly.

Good point.  At least for the "linked lists, etc" part.

But for trees and symbol tables and the like, as in a compiler,
those container libraries are no help.

- Bob



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

* Re: private types
  2006-03-21  8:07                         ` Maciej Sobczak
@ 2006-03-26 18:53                           ` Robert A Duff
  0 siblings, 0 replies; 94+ messages in thread
From: Robert A Duff @ 2006-03-26 18:53 UTC (permalink / raw)


Maciej Sobczak <no.spam@no.spam.com> writes:

> Robert A Duff wrote:
> 
> >>>Only a very few C/C++ programmers
> >>>actually master the language.
> >>
> >>As is true for any language that is at least moderately useful.
> > True.  Language designers ought to take that into account -- whenever
> > possible, try to design features subtle misunderstandings are unlikely
> > to cause bugs.
> 
> True, I don't have any doubts about it.
> 
> > Suppose an Ada programmer and a C++ programmer both think that null/NULL
> > must be represented as all-zero-bits.  Both programmers are confused.
> 
> Both programmers take assumptions which are equally wrong.

Right.

> > But which programmer is more likely to write code that won't work
> > on a machine where the assumption turns out to be false?
> 
> Naither of those programmer should have any problems with their
> programs, because pointers are, well, pointers, not integers. Neither of
> them should have any temptation to interpret pointers as numbers, so
> that the actual "value" of the pointer never really matters.

You say "should".  But we're talking about confused/wrong programmers.

But the C++ programmer has been taught to use "0" as a value of type
char* (which pointer value, of course, is not necessarily represented as
all-zero-bits).  See other posts in this thread, which recommend that
style.  It's not far from there, to (wrongly) believing that casting an
integer zero to pointer will result in null.

>... Even the
> question "is the NULL pointer zero?" makes no sense in this light,
> unless you target specific piece of silicon (see my replies to Martin
> Krischik).

I agree that the question "is the NULL pointer zero?" makes no sense,
but the question "is the NULL pointer represented as zero (in some or
all implementations of a certain language)?" makes sense.

It's not usually a hardware ("silicon") issue, though.
Ada compilers choose to represent null as zero because compilers
for other languages do that, and because operating systems arrange
for page zero to trap.  Also, I think there are some minor efficiency
advantages.

> In practice, in the world of pointers it's not the NULL pointer
> representation which is causing problems, but rather unconstrained
> pointer arithmetics.

Certainly pointer arithmetic adds extra trouble.  But even without that,
dereferencing of null pointers is a plentiful source of bugs.

- Bob



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

* Re: private types
  2006-03-26 16:51                       ` Robert A Duff
@ 2006-03-26 19:41                         ` Jeffrey R. Carter
  0 siblings, 0 replies; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-26 19:41 UTC (permalink / raw)


Robert A Duff wrote:
> 
> An uninit var should be considered a bug, whether it's access or
> integer.  I see no fundamental difference, here.  Defaulting to null
> hides this bug.

This only holds true for types that don't have meaningful default initial 
values. I've written lots of types for which an uninitialized variable of the 
type is perfectly reasonable, and even the expected behavior. Usually they're 
defined as "[limited] private". I don't expect users of a data structure to have 
to make a special initialization call to be able to use the structure.

Whether the default initial value for access types is a good choice is not 
something I'm debating. I'm simply saying that default initial values are not a 
bad thing for ADTs, an access type is closer to an ADT than to a scalar type, 
and using the same criteria for both doesn't compute.

> Yes, but my claim is that that's a poorly designed abstraction.
> In most cases, null is just a tripping hazard.
> The programmer should have the choice -- access type without
> any special value, access type with a special value that doesn't
> designate anything, access type with _two_ special values, ...

That may be, but because it's an abstraction, it's not similar to scalar types, 
and so arguments that apply to scalar types don't necessarily apply.

> Note that when I declare a private type, I choose whether it should have
> "special" values, and what they mean.  And I choose whether a special
> value is used as a default.  I can choose to raise an exception if
> clients look at an uninit var.  I can choose to prevent uninit
> vars statically, using (<>) discriminants.

Access types are like a private type. The only difference is that access types 
are part of the core language, and don't carry all the extra syntax that 
defining them as an explicit private type would add. Ichbiah and company chose 
that the abstraction called access types should have a "special" value, and what 
it means. They chose that a special value is used as a default. They chose to 
raise an exception if clients apply certain operations to an uninitialized 
variable. They may not be the choices you would make for this abstraction, but 
your choices may not be what others would choose, also.

-- 
Jeff Carter
"My name is Jim, but most people call me ... Jim."
Blazing Saddles
39



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

* Re: private types
  2006-03-26 18:28                   ` Robert A Duff
@ 2006-03-26 19:43                     ` Jeffrey R. Carter
  2006-03-26 19:59                     ` Simon Wright
  1 sibling, 0 replies; 94+ messages in thread
From: Jeffrey R. Carter @ 2006-03-26 19:43 UTC (permalink / raw)


Robert A Duff wrote:
> 
> But for trees and symbol tables and the like, as in a compiler,
> those container libraries are no help.

I would think by now you would have created domain-specific packages to 
encapsulate these concepts for your language-processing tool development work, 
and still not have to deal directly with the access types.

-- 
Jeff Carter
"My name is Jim, but most people call me ... Jim."
Blazing Saddles
39



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

* Re: private types
  2006-03-26 18:28                   ` Robert A Duff
  2006-03-26 19:43                     ` Jeffrey R. Carter
@ 2006-03-26 19:59                     ` Simon Wright
  1 sibling, 0 replies; 94+ messages in thread
From: Simon Wright @ 2006-03-26 19:59 UTC (permalink / raw)


Robert A Duff <bobduff@shell01.TheWorld.com> writes:

> But for trees and symbol tables and the like, as in a compiler,
> those container libraries are no help.

What is so special about trees and symbol tables? (I can see that
application-specific optimisation might be a problem).



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

* Re: private types
  2006-03-19 20:43                     ` Dr. Adrian Wrigley
  2006-03-20 15:01                       ` Robert A Duff
@ 2006-03-27  4:07                       ` Dave Thompson
  1 sibling, 0 replies; 94+ messages in thread
From: Dave Thompson @ 2006-03-27  4:07 UTC (permalink / raw)


--
On Sun, 19 Mar 2006 20:43:42 GMT, "Dr. Adrian Wrigley"
<amtw@linuxchip.demon.co.uk.uk.uk> wrote:

> On Sun, 19 Mar 2006 20:20:52 +0100, Martin Krischik wrote:
(C++ null pointers not all-bits-zero, also true of C)
> > Super! And how many (in %) of C++ programmer actually know that. By guess is
> > 0.1%. And indeed I is the main problem: Only a very few C/C++ programmers
> > actually master the language. 
> 
Languages, or either language. C++ is not C much as Ada is not Pascal.

> It is (or was) quite a common interview question, to see if
> C (and C++) programmers know their subject properly.  As you
> say, Robert, most don't.
> 
I don't know how common it is on interviews, having neither attended
nor given any for quite some time. It is several FAQs on comp.lang.c.

> A related topic is the issue of pointer representation, which
> (IIRC) says that pointers to char (any kind) and void have to be
> the same.  Pointers to functions have to be the same.  But all

Pointers to char and void the same, yes. Separately pointers to all
structs, and to all unions; this allows using them for 'incomplete'
types, almost (not fully) like Ada private.

Pointers to functions, not completely. Pointers to differently
prototyped functions are different types, and calling a function
through a wrong-type pointer is Undefined Behavior (= erroneous = not
required to be caught/diagnosed or to do anything even remotely
reasonable). However, any function that is or could have been defined
in nonprototype aka K&R1 aka oldstyle form must be callable using a
(K&R1-style) 'pointer to function of unspecified arguments'. In
practice this means that most systems use a compatible calling
sequence for at least all nonvarargs functions, so pointers to any of
them actually work interchangeably. I have seen platforms, but only a
handful, where varargs are different, and mixing pointers to them (or
misdeclaring) does cause (serious) problems.

> other pointers can have their own representation.  All pointers
> can be converted to and from pointers to void, without loss.  And

All _data_ pointers can be converted to and from void* without loss.
All function pointers can  be converted to other function pointers
without loss; at least formally you must convert back before using.

> pointers can have different sizes and different patterns for the
> null pointer.  I suspect a lot of code would fail if compilers
> wanted to exercise their full freedoms!

Agree with both of those.

- David.Thompson1 at worldnet.att.net



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

end of thread, other threads:[~2006-03-27  4:07 UTC | newest]

Thread overview: 94+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-03-13 19:58 private types ada_student
2006-03-13 20:27 ` Mark Lorenzen
2006-03-13 21:05   ` Pascal Obry
2006-03-13 21:07   ` ada_student
2006-03-13 21:45     ` Simon Wright
2006-03-14  4:51 ` Jeffrey R. Carter
2006-03-14  7:44   ` Brian May
2006-03-14  8:25     ` Ludovic Brenta
2006-03-14  8:47     ` Alex R. Mosteo
2006-03-17  4:33     ` Justin Gombos
2006-03-17  5:17       ` Brian May
2006-03-17 22:50         ` Justin Gombos
2006-03-18  1:17         ` Randy Brukardt
2006-03-18  2:17           ` Justin Gombos
2006-03-21  0:08             ` Randy Brukardt
2006-03-18  8:39           ` Uninitialized variables (was: Re: private types) Dirk Craeynest
2006-03-18 14:06             ` Gautier
2006-03-18 14:36               ` Uninitialized variables Jeffrey Creem
2006-03-21  0:22             ` Uninitialized variables (was: Re: private types) Randy Brukardt
2006-03-21  0:38             ` Randy Brukardt
2006-03-18 12:06           ` private types Martin Dowie
2006-03-18 12:47           ` Robert A Duff
2006-03-17  7:40       ` Maciej Sobczak
2006-03-17 16:41         ` Frank J. Lhota
2006-03-17 23:36         ` Justin Gombos
2006-03-18  1:32           ` Randy Brukardt
2006-03-18  3:21             ` Handling invalid objects Justin Gombos
2006-03-18  7:35               ` Jeffrey R. Carter
2006-03-18 16:10                 ` Justin Gombos
2006-03-19 11:00                   ` Simon Wright
2006-03-20 23:57                   ` Randy Brukardt
2006-03-22  2:06                     ` Justin Gombos
2006-03-22  5:23                       ` tmoran
2006-03-22  8:48                         ` Dmitry A. Kazakov
2006-03-22  9:24                           ` Maciej Sobczak
2006-03-22 11:05                             ` Dmitry A. Kazakov
2006-03-22 16:42                               ` Maciej Sobczak
2006-03-22 18:06                                 ` Stefan Lucks
2006-03-23 13:20                                 ` Dmitry A. Kazakov
2006-03-18  8:57               ` Jacob Sparre Andersen
2006-03-19 19:07                 ` Dr. Adrian Wrigley
2006-03-20 15:25                   ` Robert A Duff
2006-03-19 22:06               ` Brian May
2006-03-20 21:17                 ` Jeffrey R. Carter
2006-03-20 23:44               ` Randy Brukardt
2006-03-22  1:27                 ` Justin Gombos
2006-03-18  9:20           ` private types Dmitry A. Kazakov
2006-03-17 13:18       ` Robert A Duff
2006-03-17 23:44         ` Justin Gombos
2006-03-18  9:24           ` Dmitry A. Kazakov
2006-03-18 12:56           ` Robert A Duff
2006-03-18 15:06             ` Justin Gombos
2006-03-19  9:35               ` Martin Krischik
2006-03-19 14:52                 ` Peter C. Chapin
2006-03-19 15:08                   ` Björn Persson
2006-03-19 16:34                     ` Martin Krischik
2006-03-20  9:57                       ` Maciej Sobczak
2006-03-20 10:58                         ` Peter C. Chapin
2006-03-20 11:19                           ` Peter C. Chapin
2006-03-20 13:06                           ` Maciej Sobczak
2006-03-20 15:19                         ` Robert A Duff
2006-03-20 16:47                           ` James Dennett
2006-03-20 19:12                         ` Martin Krischik
2006-03-21  7:27                           ` Maciej Sobczak
2006-03-20 19:32                         ` Martin Krischik
2006-03-21  7:41                           ` Maciej Sobczak
2006-03-20 20:29                       ` Simon Wright
2006-03-19 17:43                     ` Larry Kilgallen
2006-03-19 22:11                     ` Peter C. Chapin
2006-03-19 18:15                 ` Robert A Duff
2006-03-19 19:20                   ` Martin Krischik
2006-03-19 20:43                     ` Dr. Adrian Wrigley
2006-03-20 15:01                       ` Robert A Duff
2006-03-27  4:07                       ` Dave Thompson
2006-03-20  9:40                     ` Maciej Sobczak
2006-03-20 15:09                       ` Robert A Duff
2006-03-21  8:07                         ` Maciej Sobczak
2006-03-26 18:53                           ` Robert A Duff
2006-03-19 19:27                 ` Jeffrey R. Carter
2006-03-25 21:40               ` Robert A Duff
2006-03-26  0:10                 ` Justin Gombos
2006-03-26  1:00                   ` Robert A Duff
2006-03-26  6:37                     ` Jeffrey R. Carter
2006-03-26 15:43                       ` Justin Gombos
2006-03-26 16:32                         ` Robert A Duff
2006-03-26 16:51                       ` Robert A Duff
2006-03-26 19:41                         ` Jeffrey R. Carter
2006-03-26  3:15                 ` Frank J. Lhota
2006-03-26 18:28                   ` Robert A Duff
2006-03-26 19:43                     ` Jeffrey R. Carter
2006-03-26 19:59                     ` Simon Wright
  -- strict thread matches above, loose matches on Subject: below --
1999-01-25  0:00 Uninitialized Variables Roger Racine
1999-01-25  0:00 ` robert_dewar
1999-01-25  0:00 ` Tucker Taft

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