comp.lang.ada
 help / color / mirror / Atom feed
* Discriminated types with default discriminants
@ 2005-11-03 15:50 Maciej Sobczak
  2005-11-03 16:06 ` Martin Krischik
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Maciej Sobczak @ 2005-11-03 15:50 UTC (permalink / raw)


Hi,

Consider this:

procedure Hello is

    type Discriminated(Size : Integer := 10) is
       record
          Value : String (1..Size);
       end record;

    S : Discriminated;

begin
    null;
end Hello;


Compiler (GNAT) gives me two warnings:

      5.          Value : String (1..Size);
                                     |
         >>> warning: creation of object of this type may raise 
Storage_Error

      8.    S : Discriminated;
            |
         >>> warning: Storage_Error will be raised at run-time


Moreover, it keeps a promise and indeed the program raises STORAGE_ERROR 
at run-time.

What's happening here? Why the object S is not created with 10 as the 
default discriminant?

I can get rid of the second warning by declaring S as:

S : Discriminated(10);

Indeed - program runs fine (i.e. it does not raise any exception). 
What's the difference?


I can get rid of the first warning with this:

    subtype MyInt is Integer;
    type Discriminated(Size : MyInt := 10) is
    -- ...

What's the difference?


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



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

* Re: Discriminated types with default discriminants
  2005-11-03 15:50 Discriminated types with default discriminants Maciej Sobczak
@ 2005-11-03 16:06 ` Martin Krischik
  2005-11-03 23:10   ` Robert A Duff
  2005-11-03 16:21 ` Ed Falis
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Martin Krischik @ 2005-11-03 16:06 UTC (permalink / raw)


Am 03.11.2005, 17:50 Uhr, schrieb Maciej Sobczak <no.spam@no.spam.com>:

> Hi,
>
> Consider this:
>
> procedure Hello is
>
>     type Discriminated(Size : Integer := 10) is
>        record
>           Value : String (1..Size);
>        end record;
>
>     S : Discriminated;
>
> begin
>     null;
> end Hello;
>
>
> Compiler (GNAT) gives me two warnings:
>
>       5.          Value : String (1..Size);
>                                      |
>          >>> warning: creation of object of this type may raise  
> Storage_Error
>
>       8.    S : Discriminated;
>             |
>          >>> warning: Storage_Error will be raised at run-time
>
>
> Moreover, it keeps a promise and indeed the program raises STORAGE_ERROR  
> at run-time.
>
> What's happening here? Why the object S is not created with 10 as the  
> default discriminant?

Because you might store a larger object later. So - at least GNAT -  
allocate as much memory as needed for the larges possible object - thats 2  
GB.

Hint 1: unless this is homework: use Bounded_String or Unbounded_String -  
don't reinvent the wheel.

Hint 2: try "type MyInt is range 0 .. 1000;" or whatever upper limit is  
sensible.

Martin

Links:
   http://en.wikibooks.org/wiki/Ada_Programming/Strings



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

* Re: Discriminated types with default discriminants
  2005-11-03 15:50 Discriminated types with default discriminants Maciej Sobczak
  2005-11-03 16:06 ` Martin Krischik
@ 2005-11-03 16:21 ` Ed Falis
  2005-11-03 17:28 ` Dmitry A. Kazakov
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Ed Falis @ 2005-11-03 16:21 UTC (permalink / raw)


GNAT attempts to allocate the maximum size when an object with a defaulted  
discriminant is declared, since different sized values can be assigned to  
it.  The alternative, used in the old Alsys compilers, is to allocate for  
the defaulted size, then perform reallocation during assignment if a  
differently sized value is assigned.  Both approaches are allowed  
implementations with different tradeoffs.



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

* Re: Discriminated types with default discriminants
  2005-11-03 15:50 Discriminated types with default discriminants Maciej Sobczak
  2005-11-03 16:06 ` Martin Krischik
  2005-11-03 16:21 ` Ed Falis
@ 2005-11-03 17:28 ` Dmitry A. Kazakov
  2005-11-03 18:51 ` Jeffrey R. Carter
  2005-11-04  3:27 ` Brian May
  4 siblings, 0 replies; 15+ messages in thread
From: Dmitry A. Kazakov @ 2005-11-03 17:28 UTC (permalink / raw)


On Thu, 03 Nov 2005 16:50:12 +0100, Maciej Sobczak wrote:

> Consider this:
> 
> procedure Hello is
> 
>     type Discriminated(Size : Integer := 10) is
>        record
>           Value : String (1..Size);
>        end record;
> 
>     S : Discriminated;
> 
> begin
>     null;
> end Hello;
> 
> 
> Compiler (GNAT) gives me two warnings:
> 
>       5.          Value : String (1..Size);
>                                      |
>          >>> warning: creation of object of this type may raise 
> Storage_Error
> 
>       8.    S : Discriminated;
>             |
>          >>> warning: Storage_Error will be raised at run-time
> 
> 
> Moreover, it keeps a promise and indeed the program raises STORAGE_ERROR 
> at run-time.
> 
> What's happening here? Why the object S is not created with 10 as the 
> default discriminant?
> 
> I can get rid of the second warning by declaring S as:
> 
> S : Discriminated(10);
> 
> Indeed - program runs fine (i.e. it does not raise any exception). 
> What's the difference?
> 
> I can get rid of the first warning with this:
> 
>     subtype MyInt is Integer;
>     type Discriminated(Size : MyInt := 10) is
>     -- ...
> 
> What's the difference?

No difference, just another GNAT's "feature", GNAT will raise Storage_Error 
at run-time.

What will indeed make difference is this:

   subtype Expected_Sizes is Natural range 0..1000;
   type Discriminated (Size : Expected_Sizes := 10) is record
      Value : String (1..Size);
    end record;

But better is to remove the default value.

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



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

* Re: Discriminated types with default discriminants
  2005-11-03 15:50 Discriminated types with default discriminants Maciej Sobczak
                   ` (2 preceding siblings ...)
  2005-11-03 17:28 ` Dmitry A. Kazakov
@ 2005-11-03 18:51 ` Jeffrey R. Carter
  2005-11-03 23:08   ` Robert A Duff
  2005-11-04  9:18   ` Maciej Sobczak
  2005-11-04  3:27 ` Brian May
  4 siblings, 2 replies; 15+ messages in thread
From: Jeffrey R. Carter @ 2005-11-03 18:51 UTC (permalink / raw)


Maciej Sobczak wrote:

>    type Discriminated(Size : Integer := 10) is
>       record
>          Value : String (1..Size);
>       end record;

Aside : begin

When I see something like this, I always wonder: What does a negative Size mean?

To my mind, a negative Size is meaningless, and should not be allowed:

Size : Natural

end Aside;

There are 3 cases with discriminants:

1. No default (object must be declared with explicit value)
2. Default, and object declared with explicit value
3. Default, and object declared without explicit value

The 1st 2 cases are equivalent. The object must always have the same value for 
the discriminant. It can never change. The object is constrained.

The last case means the discriminant can change. The object is unconstrained.

Given

subtype V_Index is Natural range 0 .. 255;

type V_String (Length : V_Index := 0) is record
    Data : String (1 .. Length) := String'(1 .. Length => 'J');
end record;

V : V_String;

one can later change the Length of V:

V := V_String'(Length => 23, Data => String'(1 .. 23 => 'C') );

There are 2 ways the compiler may implement this. Many compilers, including 
GNAT, allocate enough storage for the largest value, and then use parts of this 
storage depending on the current value of the discriminant. If the largest value 
is too big, such a declaration results in Storage_Error being raised.

A few compilers will add a level of indirection, and store the variable-sized 
stuff elsewhere, reallocating storage when the amount available is not big 
enough. I think RR Software's Janus Ada compiler does this. With this scheme, 
you only get Storage_Error if you actually try to store a value that is too big.

As with most implementation decisions, it's a trade off among complexity, space, 
and time.

-- 
Jeff Carter
"Now go away or I shall taunt you a second time."
Monty Python & the Holy Grail
07



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

* Re: Discriminated types with default discriminants
  2005-11-03 18:51 ` Jeffrey R. Carter
@ 2005-11-03 23:08   ` Robert A Duff
  2005-11-04  0:08     ` Adam Beneschan
  2005-11-04  9:18   ` Maciej Sobczak
  1 sibling, 1 reply; 15+ messages in thread
From: Robert A Duff @ 2005-11-03 23:08 UTC (permalink / raw)


"Jeffrey R. Carter" <spam@spam.com> writes:

> There are 2 ways the compiler may implement this. Many compilers,
> including GNAT, allocate enough storage for the largest value, and then
> use parts of this storage depending on the current value of the
> discriminant. If the largest value is too big, such a declaration
> results in Storage_Error being raised.
> 
> A few compilers will add a level of indirection, and store the
> variable-sized stuff elsewhere, reallocating storage when the amount
> available is not big enough.

It is quite difficult to get the indirect approach to work right.
Think about renaming a subcomponent of the thing, or taking
'Access of a subcomponent.  Then the thing moves elsewhere in
the heap when it grows.  Bad news!  I've seen compiler bugs
in this area.

> As with most implementation decisions, it's a trade off among
> complexity, space, and time.

Indeed.

- Bob



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

* Re: Discriminated types with default discriminants
  2005-11-03 16:06 ` Martin Krischik
@ 2005-11-03 23:10   ` Robert A Duff
  2005-11-04  5:01     ` Jeffrey R. Carter
  0 siblings, 1 reply; 15+ messages in thread
From: Robert A Duff @ 2005-11-03 23:10 UTC (permalink / raw)


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

> Hint 1: unless this is homework: use Bounded_String or Unbounded_String
> -
> don't reinvent the wheel.

Well, that's usually good advice, but I had a case where changing a
single Bounded_String to my own buffer type increased speed by two
orders of magnitude.  It depends on the program, of course.
Initializing Bounded_Strings is surprisingly slow.

- Bob



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

* Re: Discriminated types with default discriminants
  2005-11-03 23:08   ` Robert A Duff
@ 2005-11-04  0:08     ` Adam Beneschan
  2005-11-29  2:49       ` Randy Brukardt
  0 siblings, 1 reply; 15+ messages in thread
From: Adam Beneschan @ 2005-11-04  0:08 UTC (permalink / raw)


Robert A Duff wrote:

> > A few compilers will add a level of indirection, and store the
> > variable-sized stuff elsewhere, reallocating storage when the amount
> > available is not big enough.
>
> It is quite difficult to get the indirect approach to work right.
> Think about renaming a subcomponent of the thing,

Ummm ... isn't this exactly what's disallowed by 8.5.1(5)?

                                          -- Adam




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

* Re: Discriminated types with default discriminants
  2005-11-03 15:50 Discriminated types with default discriminants Maciej Sobczak
                   ` (3 preceding siblings ...)
  2005-11-03 18:51 ` Jeffrey R. Carter
@ 2005-11-04  3:27 ` Brian May
  2005-11-04 13:09   ` Stephen Leake
  2005-11-04 17:58   ` Martin Krischik
  4 siblings, 2 replies; 15+ messages in thread
From: Brian May @ 2005-11-04  3:27 UTC (permalink / raw)


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

Hello,

The 2nd warning has already been explained in detail, however I am
still confused with the first warning:

    Maciej> Compiler (GNAT) gives me two warnings:

    Maciej> 5.          Value : String (1..Size);
    Maciej> |
    >>>> warning: creation of object of this type may raise
    Maciej> Storage_Error

Why does this warning go away when using an unbounded subtype? Doesn't
the issue still exist?

    Maciej> I can get rid of the first warning with this:

    Maciej> subtype MyInt is Integer;
    Maciej> type Discriminated(Size : MyInt := 10) is
    Maciej> -- ...

Thanks
-- 
Brian May <bam@snoopy.apana.org.au>



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

* Re: Discriminated types with default discriminants
  2005-11-03 23:10   ` Robert A Duff
@ 2005-11-04  5:01     ` Jeffrey R. Carter
  0 siblings, 0 replies; 15+ messages in thread
From: Jeffrey R. Carter @ 2005-11-04  5:01 UTC (permalink / raw)


Robert A Duff wrote:

> Well, that's usually good advice, but I had a case where changing a
> single Bounded_String to my own buffer type increased speed by two
> orders of magnitude.  It depends on the program, of course.
> Initializing Bounded_Strings is surprisingly slow.

Yikes! Which compiler(s)?

-- 
Jeff Carter
"Now go away or I shall taunt you a second time."
Monty Python & the Holy Grail
07



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

* Re: Discriminated types with default discriminants
  2005-11-03 18:51 ` Jeffrey R. Carter
  2005-11-03 23:08   ` Robert A Duff
@ 2005-11-04  9:18   ` Maciej Sobczak
  1 sibling, 0 replies; 15+ messages in thread
From: Maciej Sobczak @ 2005-11-04  9:18 UTC (permalink / raw)


Jeffrey R. Carter wrote:

> Aside : begin
> 
> When I see something like this, I always wonder: What does a negative 
> Size mean?
> 
> To my mind, a negative Size is meaningless, and should not be allowed:
> 
> Size : Natural
> 
> end Aside;

Sure - no need to worry. :)
Just trying discriminated types: I picked Integer since the actual type 
would depend on the domain and without any particular domain (not even a 
homework) there was no reason to focus on type choices.


> There are 3 cases with discriminants:
> 
> 1. No default (object must be declared with explicit value)
> 2. Default, and object declared with explicit value
> 3. Default, and object declared without explicit value
> 
> The 1st 2 cases are equivalent. The object must always have the same 
> value for the discriminant. It can never change. The object is constrained.
> 
> The last case means the discriminant can change. The object is 
> unconstrained.

*Now* it all makes sense. I understand that for that last case the 
default discriminant value is actually used (I got an impression that 
it's not used at all), but is not considered to be fixed nor limiting - 
this is what "unconstrained" means in this context. It is the 
discriminant's *type* that defines the range of sizes for the final 
object and that's why I got the warning about the possibility of getting 
storage error.

This:

    subtype MyInt is Integer;
    type Discriminated(Size : MyInt := 10) is

makes the warning go away (GNAT's "feature" - as explained by Dmitry), 
but does not change anything from the language point of view - the 
potential size of the object still depends on MyInt'Last and if the 
actual object is unconstrained, we get memory allocation problem due to 
the fact that GNAT chooses one particular way of managing memory for 
unconstrained objects.

Thanks for the explanation.

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



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

* Re: Discriminated types with default discriminants
  2005-11-04  3:27 ` Brian May
@ 2005-11-04 13:09   ` Stephen Leake
  2005-11-04 17:58   ` Martin Krischik
  1 sibling, 0 replies; 15+ messages in thread
From: Stephen Leake @ 2005-11-04 13:09 UTC (permalink / raw)


Brian May <bam@snoopy.apana.org.au> writes:

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

> I am
> still confused with the first warning:
>
>
>     Maciej> 5.          Value : String (1..Size);
>     Maciej> |
>     >>>> warning: creation of object of this type may raise
>     Maciej> Storage_Error
>
> Why does this warning go away when using an unbounded subtype? Doesn't
> the issue still exist?
>
>     Maciej> I can get rid of the first warning with this:
>
>     Maciej> subtype MyInt is Integer;
>     Maciej> type Discriminated(Size : MyInt := 10) is
>     Maciej> -- ...

This is just a compiler bug. It assumes that since you specified a
subtype, things are ok, and suppresses the warning.

Note that 'warnings' are not defined by the language; they are
provided by the compiler implementor in an attempt to make the
compiler easier to use.

You could report this to AdaCore (send an email to report@gnat.com);
they typically take warning and error message issues seriously, since
that is a good marketing point.

-- 
-- Stephe



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

* Re: Discriminated types with default discriminants
  2005-11-04  3:27 ` Brian May
  2005-11-04 13:09   ` Stephen Leake
@ 2005-11-04 17:58   ` Martin Krischik
  1 sibling, 0 replies; 15+ messages in thread
From: Martin Krischik @ 2005-11-04 17:58 UTC (permalink / raw)


Am 04.11.2005, 05:27 Uhr, schrieb Brian May <bam@snoopy.apana.org.au>:

>>>>>> "Maciej" == Maciej Sobczak <no.spam@no.spam.com> writes:
>
> Hello,
>
> The 2nd warning has already been explained in detail, however I am
> still confused with the first warning:
>
>     Maciej> Compiler (GNAT) gives me two warnings:
>
>     Maciej> 5.          Value : String (1..Size);
>     Maciej> |
>     >>>> warning: creation of object of this type may raise
>     Maciej> Storage_Error
>
> Why does this warning go away when using an unbounded subtype? Doesn't
> the issue still exist?

Indeed it still exists - only the compiler did not detect it right away.  
Note: Warnings like this are usualy created by the optimizer and are not  
part of the language.

>     Maciej> I can get rid of the first warning with this:
>
>     Maciej> subtype MyInt is Integer;
>     Maciej> type Discriminated(Size : MyInt := 10) is
>     Maciej> -- ...

Martin



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

* Re: Discriminated types with default discriminants
  2005-11-04  0:08     ` Adam Beneschan
@ 2005-11-29  2:49       ` Randy Brukardt
  2005-12-02 18:22         ` Robert A Duff
  0 siblings, 1 reply; 15+ messages in thread
From: Randy Brukardt @ 2005-11-29  2:49 UTC (permalink / raw)


"Adam Beneschan" <adam@irvine.com> wrote in message
news:1131062882.814405.147150@g44g2000cwa.googlegroups.com...
> Robert A Duff wrote:
>
> > > A few compilers will add a level of indirection, and store the
> > > variable-sized stuff elsewhere, reallocating storage when the amount
> > > available is not big enough.
> >
> > It is quite difficult to get the indirect approach to work right.
> > Think about renaming a subcomponent of the thing,
>
> Ummm ... isn't this exactly what's disallowed by 8.5.1(5)?

Yes, it is. Bob is thinking about cases where a non-discriminant component
is moved by the changing of a discriminant. (I know this because he and I
have had this particular discussion repeatedly.) An implementation like that
is bound to fail, IMHO. On the other hand, an implementation like
Janus/Ada's (in which discriminant dependent components are just descriptors
to the actual data) doesn't have this problem. (There is some complication
determining the correct storage pool to use - think about a discriminant
changing assignment on a subprogram parameter - but its not particularly
hard to get right.)

                             Randy.






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

* Re: Discriminated types with default discriminants
  2005-11-29  2:49       ` Randy Brukardt
@ 2005-12-02 18:22         ` Robert A Duff
  0 siblings, 0 replies; 15+ messages in thread
From: Robert A Duff @ 2005-12-02 18:22 UTC (permalink / raw)


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

> "Adam Beneschan" <adam@irvine.com> wrote in message
> news:1131062882.814405.147150@g44g2000cwa.googlegroups.com...
> > Robert A Duff wrote:
> >
> > > > A few compilers will add a level of indirection, and store the
> > > > variable-sized stuff elsewhere, reallocating storage when the amount
> > > > available is not big enough.
> > >
> > > It is quite difficult to get the indirect approach to work right.
> > > Think about renaming a subcomponent of the thing,
> >
> > Ummm ... isn't this exactly what's disallowed by 8.5.1(5)?
> 
> Yes, it is. Bob is thinking about cases where a non-discriminant component
> is moved by the changing of a discriminant. (I know this because he and I
> have had this particular discussion repeatedly.) An implementation like that
> is bound to fail, IMHO. On the other hand, an implementation like
> Janus/Ada's (in which discriminant dependent components are just descriptors
> to the actual data) doesn't have this problem. (There is some complication
> determining the correct storage pool to use - think about a discriminant
> changing assignment on a subprogram parameter - but its not particularly
> hard to get right.)

Thanks for replying, Randy.

When I saw Adam's note, I then recalled that you and I had had the same
discussion some years ago, and I think you pointed out the same
paragraph.  But by the time I got around to replying to Adam, I couldn't
find his note.

I may be confused on this issue.  The bug in question was years ago, and
was in an Ada 83 compiler (not Janus Ada -- as Randy explained above, it
doesn't have this bug).  I think Randy's description of what I was
thinking of is correct.  Something like this:

    type R(D: Natural := 0) is
        record
            S: String(1..D);
            Blah: Integer;
        end;

    X: R := (D => 4, S => "abcd", Blah => 5);
    Y: Integer renames X.Blah;
    
    X := (D => 5, S => "ABCDE", Blah => X.Blah);

The compiler in question allocated the whole record R on the heap,
so the stack variable X just contained an address.  When X is assigned
D=>5, it needs to grow, so the generated code would move the data
and make X point to a different spot.

But Y was implemented as the address of X.Blah, which moved, which made
Y a dangling pointer.  To fix this compiler bug, you would have
to implement renaming differently, or else do it like Randy
said above (make component S indirect, rather than the whole record R).

Many compilers won't tolerate the above example at all -- they will
try to allocate 2 billion bytes for X, and crash with Storage_Error.

- Bob



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

end of thread, other threads:[~2005-12-02 18:22 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-11-03 15:50 Discriminated types with default discriminants Maciej Sobczak
2005-11-03 16:06 ` Martin Krischik
2005-11-03 23:10   ` Robert A Duff
2005-11-04  5:01     ` Jeffrey R. Carter
2005-11-03 16:21 ` Ed Falis
2005-11-03 17:28 ` Dmitry A. Kazakov
2005-11-03 18:51 ` Jeffrey R. Carter
2005-11-03 23:08   ` Robert A Duff
2005-11-04  0:08     ` Adam Beneschan
2005-11-29  2:49       ` Randy Brukardt
2005-12-02 18:22         ` Robert A Duff
2005-11-04  9:18   ` Maciej Sobczak
2005-11-04  3:27 ` Brian May
2005-11-04 13:09   ` Stephen Leake
2005-11-04 17:58   ` Martin Krischik

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