comp.lang.ada
 help / color / mirror / Atom feed
From: "Randy Brukardt" <randy@rrsoftware.com>
Subject: Re: Problem with "limited with" in a *real* application
Date: Fri, 14 Oct 2005 18:47:57 -0500
Date: 2005-10-14T18:47:57-05:00	[thread overview]
Message-ID: <A9CdnTcDd6Em383enZ2dnUVZ_tGdnZ2d@megapath.net> (raw)
In-Reply-To: 1129302185.489627.266900@g47g2000cwa.googlegroups.com

"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1129302185.489627.266900@g47g2000cwa.googlegroups.com...
> Inside the Sizer package I have an Add procedure which adds a
> Window_Type (e.g. Button_Type, Check_Box_Type, etc) into the derived
> type to Self, which is a Sizer_Type derived type. So, I want (ideally)
> to minimize the casting, so I changed the Window type to take a
> Window_Type'Class so that any type can be accepted. Now, this forces me
> to cast the Self type in the New_Minimal_Frame procedure (See the
> Add's) to the base Sizer_Type. Now in C++ the Add function can be
> overridden (as in the case of wxGridBagSizer and they're not virtuals)
> so in the case of mapping to Ada in this current form, the programmer
> must know which Add to use, i.e. which cast to use, which is fair
> enough, but surely it would be easier to let the compiler decide?
> Should I use a 'Class type here?

Probably not. If you need overriding and/or dispatching somewhere, you'll
want to avoid 'Class. My rule of thumb is that primitives should be specific
unless you're absolutely certain that you'll never want to override them in
any child types. (And when is that true?).

You have to use a (view) type conversion (what you've been calling a "cast")
to all the operations of the parent type. That's just the way you write that
in Ada. OTOH, it's usually not necessary to do that for most operations,
because they are inherited, and you can just call them for the type itself.

> So, with this in mind, it's a possibility that all of the wxAda
> primitives could take 'Class types so that no casting is ever needed,
> but surely this is wrong, Ada-wise?

It's probably wrong, but I'd have to see your entire design to know for
sure. Which I'd rather not do...

> The format of the following code might get a bit screwed by Google:
>
> <wx.Core.Sizer>
> package wx.Core.Sizer is
>
>   -- This is the actual type (wxSizer) we are creating here.
>   type Sizer_Type is new Object_Type with private;

-- All of the (primitive) operations of the parent type are inherited here,
-- so you can call them without using any type conversions.

>   procedure Add(
>     Self       : in out Sizer_Type;
>     Window     : in Window_Type'Class;
>     Proportion : in Sizer_Proportion_Type := 0;
>     Flags      : in Sizer_Flag_Type := 0;
>     Border     : in Integer := 0);
>
> end wx.Core.Sizer;
> </wx.Core.Sizer>
>
> <Minimal_Frame>
> package body Minimal_Frame is
>
>   procedure New_Minimal_Frame(Self : in out Minimal_Frame_Type) is
>
>     procedure Button_Connect is new
> wxEvtHandler.Connect(Command_Event_Function);
>     procedure Check_Box_Connect is new
> wxEvtHandler.Connect(Command_Event_Function);
>     procedure My_Test_Connect is new
> wxEvtHandler.Connect(On_My_Test_Function);
>     procedure Slider_Connect is new
> wxEvtHandler.Connect(Scroll_Event_Function);
>     procedure Size_Connect is new
> wxEvtHandler.Connect(Size_Event_Function);
>     procedure Paint_Connect is new
> wxEvtHandler.Connect(Paint_Event_Function);
>
>     Field_Widths : Field_Widths_Array(0 .. 1) := (-3, -1);
>
>     package Address_To_Object is new
> System.Address_To_Access_Conversions(Minimal_Frame_Type);
>     use Address_To_Object;
>
>   begin
>
>     New_Frame(Self, ID_ANY, "Minimal wxAda App", Point_Type'(400,
> 300));
>     Text_IO.Put_Line("Self'Access : " &
> System.Address_Image(To_Address(Self'Access)));
>
>     New_Panel(Self.Panel, Window_Type(Self), Id_Any);

Here, the second parameter of New_Panel probably should be class-wide. A
subprogram with two specific different tagged types as parameters is almost
always wrong. (Dmitry will tell you why in excrutating details if you want
to know. :-)

>     New_Validator(Self.Validator);
>
>     New_Button(Self.Button, Window_Type(Self.Panel),
> Id_Type(Id_Test_Button), "Test &Button", Default_Position,
> Default_Size, 0);

Same is true here. In Claw, the Create routines look something like:

     procedure Create (Button : in out Button_Type;
                                  Parent : in out Root_Window_Type'Class;
                                  Size : in Size_Type;
                                  Position : in Point_Type;
                                  ....);

>     Set_Validator(Window_Type(Self.Button), Self.Validator);

Presuming that this is an operation on the root window type, you should be
able to just call this (a Button will have inherited it).

       Set_Validator (Self.Button, Self.Validator);

(or, in C++-like notation in Ada 200Y:)
      Self.Button.Set_Validator (Self.Validator);

The latter notation avoids the need for use-clauses.

If this isn't an operation on the root window type, then there is something
wrong with your design. Either the prefix should be class-wide (and no type
conversion is needed), or it should be primitive so it is inherited (and
thus can be overridden) by other tagged types (window classes).

>     New_Check_Box(Self.Check_Box, Window_Type(Self.Panel), Id_Any,
> "Test &Check Box", Style => Check_Box_Align_Right);
>     New_Slider(Self.Slider, Window_Type(Self.Panel), Id_Any, 50, 0,
> 100, Style => Slider_Horizontal or Slider_Labels);
>     New_Spin(Self.Spin, Window_Type(Self.Panel), Id_Any, "0", Style =>
> Spin_Wrap or Spin_Arrow_Keys);
>     New_Scroll_Bar(Self.Scroll_Bar, Window_Type(Self.Panel),
> Id_Type(Id_Test_Slider));
>     Set_Scroll_Bar(Self.Scroll_Bar, 20, 10, 100, 1000);
>
>     New_Static_Box(Self.Box, Window_Type(Self.Panel), Id_Any,
> "Testing...");
>     New_Static_Box_Sizer(Self.Sizer, Self.Box'Unchecked_Access,
> Box_Sizer_Orientation_Vertical);
>     --New_Box_Sizer(Self.Sizer, Box_Sizer_Orientation_Vertical);
>     Add(Sizer_Type(Self.Sizer), Self.Button, 1, Sizer_Expand or
> Sizer_Border_All, 5);
>     Add(Sizer_Type(Self.Sizer), Self.Check_Box, 1, Sizer_Expand or
> Sizer_Border_All, 5);
>     Add(Sizer_Type(Self.Sizer), Self.Slider, 1, Sizer_Expand or
> Sizer_Border_All, 5);
>     Add(Sizer_Type(Self.Sizer), Self.Spin, 1, Sizer_Expand or
> Sizer_Border_All, 5);
>     Add(Sizer_Type(Self.Sizer), Self.Scroll_Bar, 1, Sizer_Expand or
> Sizer_Border_All, 5);

I don't see any need for the conversions to Sizer_Type here. If Self.Sizer
is derived from Sizer_Type, then Add is inherited. Use that one without a
conversion. (That way, if it becomes necessary to override it in the future,
you'll use the overriding version for the type.) If it is actually
Sizer_Type, you don't need it.

The only problem is figuring out where the routine ("Add" in this case) is
declared, because you can't see inherited declarations. There are a number
of solutions to that:
1) Have a use_clause for every package that declares a type that you use. (I
hate this one myself.)
2) Use dot notation to specify that the routine comes from the package where
the type is declared;
3) or use the prefixed view call notation introduced by Ada 200Y:
    Self.Sizer.Add (Self.Scroll_Bar, 1, Sizer_Expand or Sizer_Border_All,
5);

>     New_Status_Bar(Self.Status_Bar, Window_Type(Self), Id_Any);
>     Set_Fields_Count(Self.Status_Bar, Field_Widths);
>     Set_Status_Bar(Self, Self.Status_Bar);
>     Set_Status_Text(Self.Status_Bar, "Welcome to wxAda!");
> --    Set_Status_Widths(Test_Status_Bar, Field_Widths'Length,
> Field_Widths);
>
>     Set_Size_Hints(Sizer_Type(Self.Sizer),
> Self.Panel'Unchecked_Access);
> --    Set_Sizer(Window_Type(Self.Panel), Self.Sizer'Unchecked_Access);
>     Set_Sizer(Window_Type(Self.Panel), Sizer_Type(Self.Sizer)'Access);
> --    Set_Sizer(Self.Panel, Sizer_Type(Self.Sizer));
>
>     Test_Event.New_Test_Event(Self.My_Test);
>
>     --Button_Connect(Self, Id_Type(ID_TEST_BUTTON), Id_Any,
> wx.Base.Event.Command.Button_Clicked, On_Quit'Access);
>     Button_Connect(Self, Id_Type(Id_Test_Button), Id_Any,
> Evt_Button_Clicked, On_Quit'Access);
>     --Check_Box_Connect(Self, Id_Type(ID_TEST_BUTTON), Id_Any,
> wx.Base.Event.Command.Check_Box_Clicked, On_Quit'Access);
>     Slider_Connect(Self, Id_Type(Id_Test_Slider), Id_Any,
> Evt_Scroll_Thumb_Track, On_Scroll_Top'Access);
>     Size_Connect(Self, Id_Any, Id_Any, Evt_Size, On_Size'Access);
>     --Paint_Connect(Self.Panel, Id_Any, Id_Any, Evt_Paint,
> On_Paint'Access);
>     Dump(Self);
>     My_Test_Connect(Self, Id_Any, Id_Any, Test_Event.My_Test_Event,
> On_My_Test'Access);
>
>   end New_Minimal_Frame;
>
> end Minimal_Frame;
> </Minimal_Frame>

Hope this helps.

                  Randy.






  reply	other threads:[~2005-10-14 23:47 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-11 15:17 [wxAda] Problem with "limited with" in a *real* application Lucretia
2005-10-11 21:23 ` Randy Brukardt
2005-10-12 17:06   ` Lucretia
2005-10-13 14:50     ` Lucretia
2005-10-13 16:18       ` Lucretia
2005-10-14  0:36         ` Randy Brukardt
2005-10-14 15:03           ` Lucretia
2005-10-14 23:47             ` Randy Brukardt [this message]
2005-10-15 13:48               ` Lucretia
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox