2

This question is a follow-up of the post at

Ada file operation: instantiation and exception

about writing to files in Ada.

I chose to place this question in a separate post so that it'll become visible to more people as I already accepted an answer on a slightly different issue (which was on exceptions in file handling) in that aforementioned post.

WITH Ada.Sequential_IO;
WITH Ada.Float_Text_IO;

PROCEDURE TEST is

package Seq_Float_IO is new Ada.Sequential_IO (Element_Type => Float);
X_File : Seq_Float_IO.File_Type;
File_Name : String;


procedure Open_Data(File : in out Seq_Float_IO.File_Type; 
Name : in String) is

BEGIN

   begin
      Seq_Float_IO.Open (
         File => File,
         Mode => Seq_Float_IO.Append_File,
         Name => File_Name );
   exception
      when Seq_Float_IO.Name_Error =>
      Seq_Float_IO.Create (
         File => File,
         Mode => Seq_Float_IO.Out_File,
         Name => File_Name);
   end;

END Open_Data;


x        : CONSTANT Float := 2.0;


BEGIN --main program
   Open_Data(X_File, "xvalues.dat");
   Seq_Float_IO.Write(File => X_File,Item => x);

   Seq_Float_IO.Close(File => X_File);
END TEST;

On compiling the above I get an error as follows:

  1. X_File : Seq_Float_IO.File_Type;
    1. File_Name : String; |

      unconstrained subtype not allowed (need initialization) provide initial value or explicit array bounds

I don't know 2 things:

  1. I have File_Name : String; as I want to be able to write to different files. So I want a general string and not something like:

File_Name : CONSTANT String := "one_File_Only.dat"

  1. Would it be better to save the procedure Open_Data in separate ads and adb (for the body) files?

Thanks a lot...


NEW...

I've modified the code as follows:

WITH Ada.Sequential_IO;

PROCEDURE TEST1 is

package Seq_Float_IO is new Ada.Sequential_IO (Element_Type => Float);
X_File, Y_File : Seq_Float_IO.File_Type;
Name_X : CONSTANT String := "domainvalues.dat";
Name_Y : CONSTANT String := "ordinatevalues.dat";


procedure Open_Data(File : in out Seq_Float_IO.File_Type; Name : in String) is

BEGIN

   begin
    Seq_Float_IO.Open (
         File => File,
         Mode => Seq_Float_IO.Append_File,
         Name => Name_X );
    exception
      when Seq_Float_IO.Name_Error =>
         Seq_Float_IO.Create (
            File => File,
            Mode => Seq_Float_IO.Out_File,
            Name => Name_X);
   end;

END Open_Data;


x        : CONSTANT Float := 2.0;


BEGIN --main program
   Open_Data(File => X_File, Name => Name_X);
   Seq_Float_IO.Write(File => X_File, Item => x);
   Seq_Float_IO.Close(File => X_File);

   Open_Data(File => Y_File, Name => Name_Y);
  Seq_Float_IO.Write(File => Y_File, Item => x);
  Seq_Float_IO.Close(File => Y_File);

END TEST1;

As you see I have

Seq_Float_IO.Open (
             File => File,
             Mode => Seq_Float_IO.Append_File,
             Name => Name_X );

I have put Name_X as the parameter that Name is taking but this is not right as I should be able to pass in a general name which can be either Name_X or Name_Y. Sorry guys, I can't figure out what to put here.

I would much appreciate your help. Thanks

Community
  • 1
  • 1
yCalleecharan
  • 4,656
  • 11
  • 56
  • 86
  • Why on earth do you continue to write `Name => Name_X` in the call to Open? What do you think the point of `Open_Data`'s parameters is? You're doing the right thing with `File`, now do the right thing with `Name`. Write `Name => Name`. Delete `Name_X`, `Name_Y`. Pass the actual filenames you want as literal strings in the call to `Open_Data` (see my answer below for the format). – Simon Wright Jul 03 '10 at 23:42
  • Thanks very much for your patience with me. – yCalleecharan Jul 04 '10 at 09:03
  • Yes I know that putting Name_X defeats the point of creating a procedure for the open and write process. I just didn't know what to put there. File IO in Ada seems hard and I need to study this part more carefully. Examples in books are not comprehensive...they tend to stick to straightforward file operations. – yCalleecharan Jul 04 '10 at 09:09
  • I think it's a good thing that I take away Name_X & Name_Y and pass actual filenames as you suggested in order to simplify the code. But I'll keep both versions so that I can learn from my mistakes. – yCalleecharan Jul 04 '10 at 09:33
  • re: patience -- sorry about that, it was rather late & I couldn't figure out what part of it was the sticking point. Anyway, that hurdle's over, good luck with the next one! – Simon Wright Jul 04 '10 at 10:41
  • To me IO operations are the sticky part when it comes to learning a language. I remember I had to go through the same experience when learning C. But I'm very glad of the help that I receive from cheerful volunteers here :). One up-vote to u as suggested by trashgod. – yCalleecharan Jul 04 '10 at 18:25

2 Answers2

3

The thing about plain String in Ada is that a particular string, like your File_Name, has to be fixed-length; but different Strings can be of different length.

You can write

S1 : String := "1234";
S2 : String := "12345";

in which case S1 is of length 4, and assignments to it have to be of length 4. You can write

S1 := "abcd";

but if you try to write

S1 := "pqrst";

or

S1 := S2;

you will get a Constraint_Error.

In the case of String parameters to subprograms, like your Open_Data, the String parameter Name takes on the length -- and of course the value! of the actual parameter in the call. So you can say

Open_Data (X_File, "x.dat");
Open_Data (Y_File, "a_very_long_name.dat");

You were having problems earlier with

procedure Open_Data(File : in out Seq_Float_IO.File_Type; 
                    Name : in String) is
begin
   Seq_Float_IO.Open (File => File,
                      Mode => Seq_Float_IO.Append_File,
                      Name => ????);

I'm reluctant to just tell you the answer, so -- consider the File => File part. The first File is the name of the formal parameter of Seq_Float_IO.Open and the second File is what is to be passed, in this case Open_Data's File parameter.

It might help if I point out that I could have written the calls above as

Open_Data (File => X_File, Name => "x.dat");
Open_Data (File => Y_File, Name => "a_very_long_name.dat");
Simon Wright
  • 25,108
  • 2
  • 35
  • 62
  • Thanks for the string explanation. I've seen in a book an example containing: File_Name : CONSTANT String := "one_File_Only.dat" as I mentioned in my post...but of course it would be helpful to extend this to any string. Thanks again. – yCalleecharan Jul 03 '10 at 21:44
2

@Simon Wright's answer is correct, and you may find it helpful to compare his answer to the second one I wrote earlier. Note that if you had

Name_X : constant String := "domainvalues.dat";
Name_Y : constant String := "ordinatevalues.dat";

Either string, Name_X or Name_Y, could be used as the actual Name parameter to Open_Data. The formal parameter, Name, is of type String. String is unconstrained, and it may be any (implementation-defined) maximum length. In contrast, Name_X and Name_Y each have a fixed length determined by their initial assignment.

Addendum: You wrote a subprogram with a formal parameter (Name) of type String, having this signature

procedure Open_Data(
    File : in out Seq_Float_IO.File_Type;
    Name : in String) is ...

In the implementation, you want to forward to Open the String you received as the actual parameter (Name), not the name of a global constant (Name_X).

Seq_Float_IO.Open (
    File => File,
    Mode => Seq_Float_IO.Append_File,
    Name => Name );
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Yes I know that putting Name_X defeats the point of creating a procedure for the open and write process. I just didn't know what to put there. File IO in Ada seems hard and I need to study this part more carefully. Examples in books are not comprehensive...they tend to stick to straighforward file operations. – yCalleecharan Jul 04 '10 at 09:09
  • Done for the up-vote. I'm starting to really like Ada. I was using C mainly and Matlab. Ada helps to avoid mistakes that can creep in easily in other languages in scientific computing. There are however few textbooks out there which show applications of Ada in numerical computing. Ada 2005 brings in new facilities for matrix operations such as calculations of eigenvalues and this is on my to-do exploration list. Thanks again. – yCalleecharan Jul 04 '10 at 18:15
  • I especially like Ada verbose style. Coming from C, Ada feels wordy but this helps a lot in program maintainability. Now I'm taking the good habit of writing long and meaningful variable names also, a thing which I was not doing when writing in C. – yCalleecharan Jul 04 '10 at 18:20