Question about "error: multiple use clauses cause hiding"

In the artificial example below, “Count” will not be visible due to multiple use clauses. Is this due to an error (somewhere) or to be considered as “normal”?


with Ada.Text_IO;
with Interfaces.C;
with Ada.Strings.Fixed;
with Ada.Exceptions;
with Ada.Strings.Unbounded;
with Ada.IO_Exceptions;
with Ada.Directories;
with Ada.Strings.Unbounded.Text_IO;
with Ada.Characters.Latin_1;
with Ada.Strings.Maps;


procedure Test1 is
   use Ada.Text_IO;
   use Ada.Directories;
   use Ada.Strings.Unbounded;
   use Ada.Strings.Unbounded.Text_IO;
   use Ada.Strings.Maps;
   use Ada.Strings;
   use Ada.Strings.Fixed;
   use all type ada.exceptions.exception_occurrence;
   i : Constant Integer := Count(Source => "AAAABBcccCCCCCCC",Set => To_Set('c'));
begin
   Put_Line("i : " & i'Image);
end Test1;

I did not try to find out which Count is meant.
The general rule about use-clauses is that all those clauses are on the same level, i.e. there is no hierarchy that the first use clause wins.

1 Like

This a result of Ada’s visibility rules. Understanding visibility is key to understanding Ada.

Simple identifiers (without a dot) are either directly visible or use-visible. Identifiers are directly visible if they are declared locally or in an enclosing declarative part. Package Standard is always an enclosing declarative part, so the identifiers in it, such as Integer and String, are directly visible (unless they are hidden).

Identifiers are use-visible if they are not directly visible, but made visible by a use clause. A directly visible identifier hides identical use-visible identifiers. In the absence of a directly visible identifier, when only one occurrence of a use-visible identifier exists, the simple name may be used. When multiple use-visible occurrences exist, they hide each other. You have to use an expanded name (with dots) to refer to such an identifier; Ada.Text_IO.Count, for example.

A good description of visibility is in Ada Distilled.

So identifiers in “standard” packages following the compiler may collide?

By the way: it seems like “Count” in Ada.Text_IO makes my test program not to compile.
It helps to remove “use Ada.Text_IO;” and prefixing the Put_Line.

There can be collisions, but since everything you do is considered a child of Standard, you usually only have to worry about collisions with package/procedure names that are at the program unit level. So you cannot name your main procedure Integer for example, since it’s full name is Standard.Integer, which would conflict with the type declaration there.

Um, no.
There is a conceptual package, Standard, which contains the “basic” types like String, Float, etc. (I say ‘conceptual’ because [IIRC] there may be no actual source-code to back it up.)

The visibility thing is essential to understanding how things work in Ada, and ties a little into the naming/structure. But a very simple example to consider is the implementation of some subsystem dealing with, say, chemical -plant control— say there’s a tank and it has a sensor named a “Float”— how do we compensate for this, while maintaining good naming?

Package Controller is

  Type Tank is private;
  Function Float( Object : Tank ) return Standard.Float;

End Controller;

Now, we could factor things out with a subtype: Subtype Reading is Standard.Float range 0.0 .. 100.0; (This, of course assumes we’re doing a percentage and not a fixed-size volume.)

True.
But Ada is really good at allowing you to rename (or subtype), and allow for sensible names to be used.

You can leave the “use” clause there, but you will need to identify which Count you mean, by prefixing it with the enclosing package name (even though you have a “use” for the package).