Sequential_IO may be instantiated with either a definite (constrained) or indefinite (unconstrained) type.
For the definite type case, the elements written to the file are simply the memory images of the data values with no control information of any kind. The resulting file should be read using the same type, no validity checking is performed on input.
For the indefinite type case, the elements written consist of two parts. First is the size of the data item, written as the memory image of a Interfaces.C.size_t value, followed by the memory image of the data value. The resulting file can only be read using the same (unconstrained) type. Normal assignment checks are performed on these read operations, and if these checks fail, Data_Error is raised. In particular, in the array case, the lengths must match, and in the variant record case, if the variable for a particular read operation is constrained, the discriminants must match.
Note that it is not possible to use Sequential_IO to write variable length array items, and then read the data back into different length arrays. For example, the following will raise Data_Error:
package IO is new Sequential_IO (String); F : IO.File_Type; S : String (1..4); ... IO.Create (F) IO.Write (F, "hello!") IO.Reset (F, Mode=>In_File); IO.Read (F, S); Put_Line (S);
On some Ada implementations, this will print hell, but the program is clearly incorrect, since there is only one element in the file, and that element is the string hello!.
In Ada 95 and Ada 2005, this kind of behavior can be legitimately achieved using Stream_IO, and this is the preferred mechanism. In particular, the above program fragment rewritten to use Stream_IO will work correctly.