1

Let's say I have a generic vector library. To make it easier to use, I want to instantiate various common forms of the vector library and make them visible in a single package.

I'm trying this:

with GenericVector;

package Vectors is
    package Vectors3 is new GenericVector(3);
    use all type Vectors3.Vector;
    subtype Vector3 is Vectors3.Vector;

    package Vectors4 is new GenericVector(4);
    use all type Vectors4.Vector;
    subtype Vector4 is Vectors4.Vector;
end;

The end goal is that I want to be able to do with Vectors; use Vectors; and end up with Vector3 and Vector4 types directly available which Just Work.

Naturally, the code above doesn't work. It looks like the use all type statements import the definitions attached to the specified type into the package specification but then those definitions aren't exported to the user of Vectors. I have to do with Vectors; use Vectors; use all type Vectors.Vectors3; instead. This is kind of sucky.

How can I do this?

David Given
  • 13,277
  • 9
  • 76
  • 123
  • 1
    The `use` clause in your package only allows you to use type inside the package, and to export the subtype you declare. You'll be able to declare a `Vector3` variable outside the package without anything else than `use Vectors`, but all operations on your subtypes are not exported so you won't be able to to `V1 + V2` outside the package. – Holt May 17 '14 at 21:46

2 Answers2

1

You could simply make Vector3 and Vector4 new types, and not just subtypes. That would implicitly declare all the inherited, primitive operations from GenericVector in Vectors.

Jacob Sparre Andersen
  • 6,733
  • 17
  • 22
  • But if I did that, they wouldn't be type compatible with `Vectors3.Vector` and `Vector4.Vector`, right? Wouldn't that cause me problems when calling methods on those types which are defined to return a `Vectors3.Vector`? – David Given May 19 '14 at 12:36
  • Yes. But why would you declare new operations on `Vectors3.Vector`, when you have `Vector3`? – Jacob Sparre Andersen May 20 '14 at 04:55
  • I'm not; I was worried that the methods defined on `GenericVector.Vector` which _returned_ a `GenericVector.Vector` would stop working. But it turns out that's not the case, and this approach works fine (although I did have some trouble with some more complex generics). Thanks. – David Given May 22 '14 at 20:30
1

use Vectors gives you direct visibility to those identifiers that are declared in Vectors, including those that are declared implicitly. (Implicit declarations are things like "+", "-", operators when you declare a new integer type, and inherited operations when you declare a derived type.) But it doesn't give you direct visibility to anything else. In particular, use is not transitive, because use all type Vectors3.Vector does not declare any new identifiers in Vectors.

You could accomplish this by declaring renaming identifiers for everything that you want a use Vectors user to see. (For types, you'd have to use subtype since there's no type renaming in Ada.) E.g. in Vectors:

function Dot_Product (V1, V2 : Vectors3.Vector) return Float
   renames Vectors3.Dot_Product;

(I'm just guessing at what the operations in GenericVectors might look like.) Now, anywhere that says use Vectors will be able to use Dot_Product directly. You'd have to do something like this for every identifier, though. If there are a lot of them, this probably isn't a viable solution. (The renaming declaration doesn't have to use the same name Dot_Product.)

Although it may seem annoying that you can't get this kind of transitive visibility, the alternative probably would turn out to be more annoying, because you can't look at Vectors and see what identifiers would be made visible by use Vectors; the result would probably be either unexpected name conflicts or other surprises.

ajb
  • 31,309
  • 3
  • 58
  • 84