Reputation: 7913
I'm fairly new to Ada, and I'm having endless problems with types, references and inclusions.
Below I have two types that need to "use" each other: Train
and Platform
, I included the source code below.
Since a direct "withing" will not work (I understand two ada types can't "see" each other directly, or a circular inclusion error will occur), I opted to have a common
package (also included below) that "limited with
"s the other two, and also implements access types so that including common
will enable a package to use pointers to Train
and Platform
.
However it seems that this is not a feasible solution either: while I can declare variables using the ref types defined in common
I cannot actually access any method/entry on them. I highlighted the troublesome line in Railway-train.adb with a comment. When the compiler reaches that line it stops with error:
Invalid prefix in selected component "StopAtPlatform"
I know that Ada is very different from other languages, but as someone that comes from C# I really have problems understanding why it is so hard to have two types using each other and why thos "pointers" (access types) seem not to be working properly. Can anyone explain what I am doing wrong?
Please, if you can, refrain from any comment such as "why do you need to have two types use each other, that's a bad practise"... thanks :)
Source follows:
Railway-train.ads
with Railway.Common; use Railway.Common;
with Ada.Text_IO; use Ada.Text_IO;
package Railway.Train is
task type Train is
entry Create(id : in Natural; capacity : in Positive; Route : Route_Array; me : Train_Ref);
end Train;
end Railway.Train;
Railway-train.adb:
package body Railway.Train is
task body Train is
Myself : Train_Ref;
Train_ID : Natural;
Passenger_Load : Integer := 0;
Passenger_Capacity : Positive;
Train_Route : Route_Array;
begin
accept Create (id : in Natural; capacity : in Positive; Route : in Route_Array; me : Train_Ref) do
Myself := me;
Train_ID := id;
Passenger_Capacity := capacity;
Train_Route := Route;
end Create;
loop
for i in Train_Route'Range loop
Train_Route(i).StopAtPlatform(Myself); --ERROR OCCOURS HERE
end loop;
end loop;
end Train;
end Railway.Train;
Railway-platform.ads:
with Railway.Common; use Railway.Common;
package Railway.Platform is
protected type Platform is
entry StopAtPlatform(Incoming_Train : in Train_Ref);
procedure DepartFromPlatform;
private
Train_At_Platform : Train_Ref := null;
end Platform;
end Railway.Platform;
railway-platform.adb:
package body Railway.Platform is
protected body Platform is
--Train occupies the platform. This stops the access to the platform by all other trains, until DepartFromPlatform is called
entry StopAtPlatform(Incoming_Train : in Train_Ref) when Train_At_Platform = null is
begin
Train_At_Platform := Incoming_Train;
end StopAtPlatform;
--Train leaves the platform. This re-opens access to the platform by all other trains
procedure DepartFromPlatform is
begin
Train_At_Platform := null;
end DepartFromPlatform;
end Platform;
end Railway.Platform;
And finally, Railway-common.ads:
limited with Railway.Platform;
limited with Railway.Train;
package Railway.Common is
--Common stuff
type Train_Ref is access all Train.Train;
type Platform_Ref is access all Platform.Platform;
type Route_Range is range 1..100;
type Route_Array is array (Route_Range) of Platform_Ref;
end Railway.Common;
EDIT: as ajb's answer below points out, adding with Railway.Platform;
on top of Railway-train.adb generates a compiler bug :(
Upvotes: 1
Views: 282
Reputation: 6611
One solution is to declare both types in the same package.
Upvotes: 0
Reputation: 31699
I think the correct answer is that you need
with Railway.Platform;
above package body Railway.Train;
. The reason is that Railway.Common
's specification defines Route_Array
as an array of Platform_Ref
, which is an access to a limited-view type (because Railway.Common
says limited with Railway.Train
and Platform
). limited with
does not make detailed information about the types in Railway.Platform
available, which is why StopAtPlatform
isn't visible. Adding a regular with
to Railway.Train
's body makes that identifier visible. It does not create a circular dependency, since it's on the body of Railway.Train
.
However, when I tried this using GNAT, the result was a bug box. I assume that's what you're using, since it gave me the exact same error message before I added the with
. So while I think this answer is correct, it may not help you until they can fix the problem.
I think the main reason why this is harder in Ada than C# is that Ada is an older language and was originally designed for the paradigm in which when you compile a file, the compiler must have all the information it needs. A source file that referred to an identifier that it hadn't yet seen (because it was in a source file that hadn't yet been compiled) wouldn't work. I think it's fair to say that the compiler technology available at the time just wasn't there yet.
EDIT: My earlier version made some misstatements about the structure of the program.
Upvotes: 1