In some cases, perhaps most or all cases, you shouldn't embed the logic that "two access-to-strings are equal if they are both null" into an abstraction (such as a package).
Consider the example where a bank transaction processing program reads the payee's name from two files, so ending up with data in Payee_Rec
and Trans_Rec
, which both have a Name
field that is an access-to-string.
In this case, null
means that the data (the payee's name) is not recorded, for some reason, in the record.
Somewhere we will check that the payee's name in both records is the same, and reject the transaction if they are not.
If the Names are of type lstring
and the test we use looks like this:
if Payee_Rec.Name /= Trans_Rec.Name then
raise Validation_Error;
end if;
then if the two names are both null, this check will pass.
But it should not! If we don't even know what the payee's name is (in both records) the transaction should fail.
So my answer, while it may seem disappointing and even off topic, is "Don't do that."
I suggest that a well-written program would use Ada.String.Unbounded.Unbounded_String
as the type (for both Name
components, in the example above). If the source of the data (e.g. a database) can have null strings (for the names), then have a separate Boolean
flag to indicate that, e.g. Name_Unknown
.
The above example check could then be written in a very clear way:
if Payee_Rec.Name_Unknown
or Trans_Rec.Name_Unknown
or Payee_Rec.Name /= Trans_Rec.Name then
raise Validation_Error;
end if;
Note that you'll need the requisite use type ...
to see the Unbounded_String
equality (and inequality) operator.
You'd probably also want to validate both names that they are not empty strings or other nonsense, and you might want to do something more sophisticated than just raising an exception if a check fails.