Bon, n'exagérons rien, je suis fort, même très fort[1] mais là, je n'y suis pas pour grand chose :D
Dans le cadre de mon petit projet de développement perso en Ada (cf. ce précédent billet), j'ai décidé de faire un niveau d'abstraction me permettant d'écrire un accord de la même façon qu'une gamme.
L'idée géniale a donc été de créer un type possédant les caractéristiques suivantes :

  • Un nom
  • Une structure correspondant à un ensemble de d'intervalles


Le type NamedStructure était né.
Désirant faire de celui-ci un type manipulable seulement au travers de procédures et fonctions, il était normal d'en faire un type privé[2].
Ensuite, la création de types Scale et Chord ne correspond qu'à définir ceux-ci comme types dérivés[3] et à réécrire les opérations de manipulations spécifiques.
En clair, cela ressemble franchement à une sorte d'héritage dans les langages purement objets.
Vous vous demandez donc certainement pourquoi je n'ai pas utilisé de classes. C'est simple, je n'ai pas besoin de faire de polymorphisme ou d'autres choses du même acabit[4] :D

Venons-en aux faits !
Lors de l'écriture de tout ce code, je suis arrivé à quelque chose du style suivant (attention, c'est long) :

with Root_Private;

package Derived_Root is
   type Derived_Root_obj(Size : Positive) is private;
   
   function Create(Name : String) return Derived_Root_obj;
   
private
   type Derived_Root_obj(Size: Positive) is new Root_Private.Root(Size);
     
end Derived_Root;
package Root_Private is
   type Root(Size : Positive) is private;
   
   function Create(Name : String) return Root;
   
private
      type Root(Size : Positive) is
	 record
	    Name : String(1..Size);
	 end record;
end Root_Private;

package body Derived_Root is
   
   function Create(Name : String) return Derived_Root_obj is
   begin
      return Derived_Root_obj(Root_Private.Create(Name));
   end Create;
   
end Derived_Root;
package body Root_Private is
   
   function Create(Name : String) return Root is
      Returned_Root : Root(Name'Length);
   begin
      Returned_Root.Name := Name;
      return Returned_Root;
   end Create;
   
end Root_Private;
with Root_Private; use Root_Private;
with Derived_Root; use Derived_Root;

procedure Test is
   My_Root : Root := Create("My test");
   My_Derived : Derived_Root_obj := Derived_Root.Create("My derived root");
begin
   null;
end Test;

Et bien, essayez donc de la compiler[5] et vous tomberez normalement sur

gnatgcc -c test.adb
+===========================GNAT BUG DETECTED==============================+
| 4.6.1 20110627 (release) -=> GNAT AUX [FreeBSD] (i386-aux-freebsd8.2) GCC error:|
| in gnat_to_gnu_entity, at ada/gcc-interface/decl.c:599                   |
| Error detected at test.adb:6:49                                          |
| Please submit a bug report; see http://gcc.gnu.org/bugs.html.            |
| Use a subject line meaningful to you and us to track the bug.            |
| Include the entire contents of this bug box in the report.               |
| Include the exact gcc or gnatmake command that you entered.              |
| Also include sources listed below in gnatchop format                     |
| (concatenated together with no headers between files).                   |
+==========================================================================+

Please include these source files with error report
Note that list may not be accurate in some cases,
so please double check that the problem can still
be reproduced with the set of files listed.
Consider also -gnatd.n switch (see debug.adb).

test.adb
root_private.ads
derived_root.ads

compilation abandoned
gnatmake: "test.adb" compilation error

Ça méritait bien un petit rapport de bug tout ça, non ?
Bon ceci dit, j'ai trouvé une parade en publiant ma classe NamedStructure (ici, Root) au lieu de la laisser en private mais je pense qu'il y a d'autres moyens plus sympas pour forcer l'encapsulation et l'utilisation des nouveaux types... c'est beau le dev :D

Notes

[1] J'ai aussi des chevilles très solides

[2] D'ailleurs, il me vient aussi l'idée d'en faire un type limité :)

[3] Et donc non compatibles entre eux

[4] Pour l'instant

[5] Enfin, il faut d'abord faire un gnatchop pour scinder en plusieurs sources