• Empty String confusion; Positive and Natural

    From Kevin Chadwick@21:1/5 to All on Mon Nov 29 09:34:47 2021
    I suspect that I am doing something outside of Ada norms.

    Are empty strings avoided in Ada?

    I have a function to create a record containing strings amongst other things like a subtyped integer, simply to group the outputs neatly of another function.

    If something goes wrong and I run the create function with "" then the strings length is zero. Why is a string type Positive and not Natural, because empty strings are in fact useless?

    I guess I shall consider re-engineering my functions, rather than add checks, but all thoughts are welcome.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jeffrey R.Carter@21:1/5 to Kevin Chadwick on Mon Nov 29 19:05:21 2021
    On 2021-11-29 18:34, Kevin Chadwick wrote:

    If something goes wrong and I run the create function with "" then the strings length is zero. Why is a string type Positive and not Natural, because empty strings are in fact useless?

    I don't understand what you're asking. 'Length returns
    universal_integer; it is independent of the index subtype. The index
    subtype can even be non-numeric.

    --
    Jeff Carter
    Programming by extension, emphasizing, as it does,
    ease of writing over ease of reading, should be
    avoided whenever possible by S/W engineers, and
    used with the same reluctance and care that they
    give to gotos and access types.
    175

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Niklas Holsti@21:1/5 to Kevin Chadwick on Mon Nov 29 21:19:16 2021
    On 2021-11-29 19:34, Kevin Chadwick wrote:
    I suspect that I am doing something outside of Ada norms.

    Are empty strings avoided in Ada?


    No, empty strings (and empty arrays in general) are quite usable.


    I have a function to create a record containing strings amongst other
    things like a subtyped integer, simply to group the outputs neatly of
    another function.


    It would clarify your question if you would show the declaration of that
    record type. Does it use the String type, or the Unbounded_String type?


    If something goes wrong and I run the create function with "" then
    the strings length is zero.


    Is there something wrong with that? An empty string should have length
    zero, it seems to me.


    Why is a string type Positive and not Natural, because empty strings
    are in fact useless?

    An object S : String is an empty string if and only if S'Length = 0.
    (And, as Jeff said, S'Length is not a Positive, but a universal integer,
    so it can be zero even if Strings are indexed with Positive numbers.)

    Also, an object S : String is an empty string if and only if S'Last <
    S'First. Note that S'Last can be much less than S'First, so in this case
    you cannot compute the length of the string from S'Last - S'First + 1.
    Or if you do, you can get a negative result, and understand that as zero length.

    The case where S'Last is much less than S'First usually comes about when
    one takes an empty slice of an existing string, for example X(5 .. 2),
    where X is for example String (1 .. 10).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Chadwick@21:1/5 to All on Mon Nov 29 14:50:25 2021
    It would clarify your question if you would show the declaration of that record type. Does it use the String type, or the Unbounded_String type?

    Hopefully I will have a doh moment when I get into the office in the morning and post code. I am getting a range check exception when I assign "" to a standard.String in a record by returning the record from a function. Surely, I must have caused it
    somehow.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ldries46@21:1/5 to All on Tue Nov 30 08:40:41 2021
    Op 29-11-2021 om 18:34 schreef Kevin Chadwick:
    I suspect that I am doing something outside of Ada norms.

    Are empty strings avoided in Ada?

    I have a function to create a record containing strings amongst other things like a subtyped integer, simply to group the outputs neatly of another function.

    If something goes wrong and I run the create function with "" then the strings length is zero. Why is a string type Positive and not Natural, because empty strings are in fact useless?

    I guess I shall consider re-engineering my functions, rather than add checks, but all thoughts are welcome.
    From your description, I suspect that you are using different
    declarations for the strings you use for instance while " " in fact is a string(1.1) you try to put this in a string(1 .. 5).
    To avoid this kind of problems I generally use the package Ada.Strings.Unbounded where have possibilities to operate strings
    without caring for the length. Changing between strings and unbounded
    strings is possible with functions in the package.
    I would then advice you to create an variable at a position where it is reachable from all packages where you use it:
    Empty_String : Unbounded_String := To_Unbounded_String("");

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Niklas Holsti@21:1/5 to Kevin Chadwick on Tue Nov 30 10:34:56 2021
    On 2021-11-30 0:50, Kevin Chadwick wrote:
    It would clarify your question if you would show the declaration of that
    record type. Does it use the String type, or the Unbounded_String type?

    Hopefully I will have a doh moment when I get into the office in the
    morning and post code. I am getting a range check exception when I
    assign "" to a standard.String

    Although Standard.String is an unconstrained array type (that is, its
    index range is defined as "Positive range <>"), every object of this
    type is constrained to a fixed length, set when the object is created.

    So if you have, for example:

    S : String (1 .. 10);

    then S'Length is always 10. If you try to assign to S a string of a
    different length, for example "", you will get an exception because the
    lengths do not match.

    If you want a string object that is flexible in terms of length, you
    should use the type Ada.Strings.Unbounded.Unbounded_String, or make an
    instance of Ada.Strings.Bounded.Bounded_String with a suitable maximum
    length.

    Or you could use a fixed-length string but always pad it with blanks (or whatever) up to the fixed length -- see Ada.Strings.Fixed for several
    useful operations on such strings. Depends on what you want...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to Kevin Chadwick on Tue Nov 30 08:29:43 2021
    Kevin Chadwick <kevc3no4@gmail.com> writes:

    It would clarify your question if you would show the declaration of
    that record type. Does it use the String type, or the
    Unbounded_String type?

    Hopefully I will have a doh moment when I get into the office in the
    morning and post code. I am getting a range check exception when I
    assign "" to a standard.String in a record by returning the record
    from a function. Surely, I must have caused it somehow.

    If you declare S : String (1 .. 5) and you want to assign a string "foo"
    to the whole of S you are forbidden to do so by the language: you have
    to assign 5 characters, no more, no fewer.

    This can be a royal pain, so we have Ada.Strings.Bounded (if you know
    the maximum length) or .Unbounded (if you don't, and can afford more
    overhead), both of which support variable-length strings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to bertus.dries@planet.nl on Tue Nov 30 08:21:28 2021
    ldries46 <bertus.dries@planet.nl> writes:

    Empty_String : Unbounded_String := To_Unbounded_String("");

    * Given the name, you should probably declare it constant.

    * You don't need to initialize it, ARM 4.5(73) [1] says "If an object of
    type Unbounded_String is not otherwise initialized, it will be
    initialized to the same value as Null_Unbounded_String".

    * Ada.Strings.Unbounded.Null_Unbounded_String is a constant empty
    string.

    [1] http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-A-4-5.html#p73

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jeffrey R.Carter@21:1/5 to Kevin Chadwick on Tue Nov 30 11:00:11 2021
    On 2021-11-29 23:50, Kevin Chadwick wrote:

    Hopefully I will have a doh moment when I get into the office in the morning and post code. I am getting a range check exception when I assign "" to a standard.String in a record by returning the record from a function. Surely, I must have caused it
    somehow.

    It sounds as if you think type String is magic. String is a
    one-dimensional array type, no different than any other one-dimensional
    array type. It is declared in ARM A.1(37/3) (http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-A-1.html) as

    type String is array(Positive range <>) of Character
    with Pack;

    If you think that

    type T is array (Positive range <>) of Integer;
    V : T (1 .. 5);
    ...
    V := (1 .. 0 => <>);

    should work, then you don't understand arrays in Ada.

    If you understand why that won't work, then

    S : String (1 .. 5);
    ...
    S := "";

    is the exact same thing and fails in the same way for the same reason.

    --
    Jeff Carter
    "I did not rob a bank. If I'd robbed a bank, everything
    would be great. I tried to rob a bank, is what happened,
    and they got me. I misspelled the note."
    Take the Money and Run
    140

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ldries46@21:1/5 to All on Tue Nov 30 13:39:28 2021
    Op 30-11-2021 om 9:21 schreef Simon Wright:
    ldries46 <bertus.dries@planet.nl> writes:

    Empty_String : Unbounded_String := To_Unbounded_String("");
    * Given the name, you should probably declare it constant.

    * You don't need to initialize it, ARM 4.5(73) [1] says "If an object of
    type Unbounded_String is not otherwise initialized, it will be
    initialized to the same value as Null_Unbounded_String".

    * Ada.Strings.Unbounded.Null_Unbounded_String is a constant empty
    string.

    [1] http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-A-4-5.html#p73
    You are right. it should be

    Empty_String : constant Unbounded_String := To_Unbounded_String("");

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Chadwick@21:1/5 to All on Tue Nov 30 04:17:19 2021
    I have a create function that returns a type RunOutput

    I always get range check failed even with a string of multiple characters.

    type RunOutput(LogLen, OutputLen : Natural) is record
    LogStr : String(0..LogLen);
    Output : String(0..OutputLen);
    ...
    end record;

    I did have the following which works, so long as the string is not empty

    type RunOutput(LogLen, OutputLen : Positive) is record
    LogStr : String(1..LogLen);
    Output : String(1..OutputLen);
    ...
    end record;


    P.s. I am not using exceptions with messages for log strings because I would rather use features that work with the zero footprint runtime as much as possible, where it makes sense.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kevin Chadwick@21:1/5 to All on Tue Nov 30 05:12:29 2021
    Since String is indexed by Positive (not Natural), the lower bound
    cannot be 0. OTOH, there is no check for bounds of empty arrays,
    therefore the following would work:
    type RunOutput(LogLen, OutputLen : Natural) is record
    LogStr : String(1..LogLen);
    Output : String(1..OutputLen);

    and you can have empty strings if Loglen or Outputlen is 0, without Constraint_Error. (It's precisely for that reason that there is no check
    of bounds of empty arrays).

    I See,
    Thanks everyone

    I apologise for posting the original thread whilst leaving the office and posting without the code upfront.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From J-P. Rosen@21:1/5 to All on Tue Nov 30 13:54:16 2021
    Le 30/11/2021 à 13:17, Kevin Chadwick a écrit :
    I have a create function that returns a type RunOutput

    I always get range check failed even with a string of multiple characters.

    type RunOutput(LogLen, OutputLen : Natural) is record
    LogStr : String(0..LogLen);
    Output : String(0..OutputLen);
    ...
    end record;

    I did have the following which works, so long as the string is not empty

    type RunOutput(LogLen, OutputLen : Positive) is record
    LogStr : String(1..LogLen);
    Output : String(1..OutputLen);
    ...
    end record;


    P.s. I am not using exceptions with messages for log strings because I would rather use features that work with the zero footprint runtime as much as possible, where it makes sense.

    Since String is indexed by Positive (not Natural), the lower bound
    cannot be 0. OTOH, there is no check for bounds of empty arrays,
    therefore the following would work:

    type RunOutput(LogLen, OutputLen : Natural) is record
    LogStr : String(1..LogLen);
    Output : String(1..OutputLen);

    and you can have empty strings if Loglen or Outputlen is 0, without Constraint_Error. (It's precisely for that reason that there is no check
    of bounds of empty arrays).
    --
    J-P. Rosen
    Adalog
    2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
    Tel: +33 1 45 29 21 52
    https://www.adalog.fr

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)