Hi, I'm trying to create a GtkAda widget derived from a standard widget. -- debug_panel.ads with Gtk.Scrolled_Window; use Gtk.Scrolled_Window; with Gtk.Text_View; use Gtk.Text_View; package Debug_Panel is type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with private; type Debug_Panel is access all Debug_Panel_Record'Class; procedure Gtk_New (Panel : in out Debug_Panel); procedure Initialize (Panel : not null access Debug_Panel_Record'Class); private type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with record Text : Gtk_Text_View; end record; end Debug_Panel; -- debug_panel.adb package body Debug_Panel is procedure Gtk_New (Panel : in out Debug_Panel) is begin Panel := new Debug_Panel_Record; Initialize (Panel); end Gtk_New; procedure Initialize (Panel : not null access Debug_Panel_Record'Class) is begin Gtk.Scrolled_Window.Initialize (Panel); -- Init other widgets end Initialize; end Debug_Panel; When compiling, I get the following error : debug_panel.adb:6:07: ambiguous expression (cannot resolve "Initialize") debug_panel.adb:6:07: possible interpretation at debug_panel.ads:15 debug_panel.adb:6:07: possible interpretation at gtk-scrolled_window.ads:92 The solution might be obvious but I don't understand why this error is raised by the compiler. Any help much appreciated. Nicolas
On 2021-04-08 21:27, DrPi wrote: > I'm trying to create a GtkAda widget derived from a standard widget. > > -- debug_panel.ads > with Gtk.Scrolled_Window; use Gtk.Scrolled_Window; > with Gtk.Text_View; use Gtk.Text_View; > > package Debug_Panel is > > type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with private; > type Debug_Panel is access all Debug_Panel_Record'Class; > > > procedure Gtk_New (Panel : in out Debug_Panel); > procedure Initialize (Panel : not null access Debug_Panel_Record'Class); > > private > > type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with record > Text : Gtk_Text_View; > end record; > > end Debug_Panel; > > > -- debug_panel.adb > package body Debug_Panel is > > procedure Gtk_New (Panel : in out Debug_Panel) is > begin > Panel := new Debug_Panel_Record; > Initialize (Panel); Debug_Panel.Initialize (Panel); Another way would be to remove "use Gtk.Scrolled_Window" and declare as type Debug_Panel_Record is new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with private; Without "use" Initialize is unambiguous. P.S. When you create new widget it is better to use a more general ancestor hiding insufficient details, e.g. type Debug_Panel_Record is new Gtk.Widget.Gtk_Widget_Record with private; ... private type Debug_Panel_Record is new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with record ... end record; This makes the code less fragile if you later decide to choose another container widget for the base. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
Le 09/04/2021 à 00:27, Dmitry A. Kazakov a écrit : > On 2021-04-08 21:27, DrPi wrote: > >> I'm trying to create a GtkAda widget derived from a standard widget. >> >> -- debug_panel.ads >> with Gtk.Scrolled_Window; use Gtk.Scrolled_Window; >> with Gtk.Text_View; use Gtk.Text_View; >> >> package Debug_Panel is >> >> type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with >> private; >> type Debug_Panel is access all Debug_Panel_Record'Class; >> >> >> procedure Gtk_New (Panel : in out Debug_Panel); >> procedure Initialize (Panel : not null access >> Debug_Panel_Record'Class); >> >> private >> >> type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with record >> Text : Gtk_Text_View; >> end record; >> >> end Debug_Panel; >> >> >> -- debug_panel.adb >> package body Debug_Panel is >> >> procedure Gtk_New (Panel : in out Debug_Panel) is >> begin >> Panel := new Debug_Panel_Record; >> Initialize (Panel); > > Debug_Panel.Initialize (Panel); I did try this notation and got this error : debug_panel.adb:6:07: invalid prefix in selected component "Debug_Panel" debug_panel.adb:6:18: prefixed call is only allowed for objects of a tagged type I've just realized this is because the package and the access type have the same name. > > Another way would be to remove "use Gtk.Scrolled_Window" and declare as > > type Debug_Panel_Record is > new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with private; > > Without "use" Initialize is unambiguous. > That makes sense. However, I don't understand why there is ambiguity when using "use". Debug_Panel (the type) is of type Debug_Panel_Record, so Initialize should resolve to the one using this type. Well, I guess I'm wrong. > P.S. When you create new widget it is better to use a more general > ancestor hiding insufficient details, e.g. > > type Debug_Panel_Record is > new Gtk.Widget.Gtk_Widget_Record with private; > ... > private > type Debug_Panel_Record is > new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with > record > ... > end record; I'm surprized this is possible to write such a thing in Ada. What does the compiler do with this ? > > This makes the code less fragile if you later decide to choose another > container widget for the base. > Thanks for your help
Le 09/04/2021 à 07:28, DrPi a écrit : >> Without "use" Initialize is unambiguous. >> > That makes sense. > However, I don't understand why there is ambiguity when using "use". > Debug_Panel (the type) is of type Debug_Panel_Record, so Initialize > should resolve to the one using this type. Well, I guess I'm wrong. No, the type is "access Debug_Panel_Record'Class", and the other initialize is for "access Gtk_Scrolled_Window_Record'Class", which covers the other one. Remember that a class wide type ('Class) is a different type that covers all descendants. >> P.S. When you create new widget it is better to use a more general >> ancestor hiding insufficient details, e.g. >> >> type Debug_Panel_Record is >> new Gtk.Widget.Gtk_Widget_Record with private; >> ... >> private >> type Debug_Panel_Record is >> new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with >> record >> ... >> end record; > > I'm surprized this is possible to write such a thing in Ada. > What does the compiler do with this ? > There is no problem, since Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record is a descendant of Gtk.Widget.Gtk_Widget_Record. There is no lie: a Debug_Panel_Record IS A Gtk_Widget_Record. The private view has more information: it actually IS A Gtk_Scrolled_Window_Record, but the extra properties are not accessible outside from the package body. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr
On 2021-04-09 07:28, DrPi wrote: > Le 09/04/2021 à 00:27, Dmitry A. Kazakov a écrit : >> On 2021-04-08 21:27, DrPi wrote: >> >>> I'm trying to create a GtkAda widget derived from a standard widget. >>> >>> -- debug_panel.ads >>> with Gtk.Scrolled_Window; use Gtk.Scrolled_Window; >>> with Gtk.Text_View; use Gtk.Text_View; >>> >>> package Debug_Panel is >>> >>> type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with >>> private; >>> type Debug_Panel is access all Debug_Panel_Record'Class; >>> >>> >>> procedure Gtk_New (Panel : in out Debug_Panel); >>> procedure Initialize (Panel : not null access >>> Debug_Panel_Record'Class); >>> >>> private >>> >>> type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with record >>> Text : Gtk_Text_View; >>> end record; >>> >>> end Debug_Panel; >>> >>> >>> -- debug_panel.adb >>> package body Debug_Panel is >>> >>> procedure Gtk_New (Panel : in out Debug_Panel) is >>> begin >>> Panel := new Debug_Panel_Record; >>> Initialize (Panel); >> >> Debug_Panel.Initialize (Panel); > I did try this notation and got this error : > debug_panel.adb:6:07: invalid prefix in selected component "Debug_Panel" > debug_panel.adb:6:18: prefixed call is only allowed for objects of a > tagged type > > I've just realized this is because the package and the access type have > the same name. You can disambiguate it so: Standard.Debug_Panel.Initialize (Panel) Standard.Debug_Panel - The package name Standard.Debug_Panel.Debug_Panel - The type name >> Another way would be to remove "use Gtk.Scrolled_Window" and declare as >> >> type Debug_Panel_Record is >> new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with private; >> >> Without "use" Initialize is unambiguous. >> > That makes sense. > However, I don't understand why there is ambiguity when using "use". > Debug_Panel (the type) is of type Debug_Panel_Record, so Initialize > should resolve to the one using this type. Well, I guess I'm wrong. Debug_Panel belongs to both Debug_Panel_Record'Class and Gtk_Scrolled_Window_Record'Class (and many other classes), so the ambiguity. >> P.S. When you create new widget it is better to use a more general >> ancestor hiding insufficient details, e.g. >> >> type Debug_Panel_Record is >> new Gtk.Widget.Gtk_Widget_Record with private; >> ... >> private >> type Debug_Panel_Record is >> new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with >> record >> ... >> end record; > > I'm surprized this is possible to write such a thing in Ada. > What does the compiler do with this ? The public view is Gtk_Widget_Record [with no record members], the full view is Gtk_Scrolled_Window_Record [with record members you specified]. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
Le 09/04/2021 à 08:12, J-P. Rosen a écrit : > Le 09/04/2021 à 07:28, DrPi a écrit : >>> Without "use" Initialize is unambiguous. >>> >> That makes sense. >> However, I don't understand why there is ambiguity when using "use". >> Debug_Panel (the type) is of type Debug_Panel_Record, so Initialize >> should resolve to the one using this type. Well, I guess I'm wrong. > No, the type is "access Debug_Panel_Record'Class", and the other > initialize is for "access Gtk_Scrolled_Window_Record'Class", which > covers the other one. > What I mean is that one "Initialize" procedure has a parameter of type "access Debug_Panel_Record'Class" and the other of type "access Gtk_Scrolled_Window_Record'Class". The call to "Initialize" is made with a "Debug_Panel" type which is an access to "Debug_Panel_Record'Class" not " an access to "Gtk_Scrolled_Window_Record'Class". So, why is there an ambiguity here ? > Remember that a class wide type ('Class) is a different type that covers > all descendants. > >>> P.S. When you create new widget it is better to use a more general >>> ancestor hiding insufficient details, e.g. >>> >>> type Debug_Panel_Record is >>> new Gtk.Widget.Gtk_Widget_Record with private; >>> ... >>> private >>> type Debug_Panel_Record is >>> new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with >>> record >>> ... >>> end record; >> >> I'm surprized this is possible to write such a thing in Ada. >> What does the compiler do with this ? >> There is no problem, since > Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record is a descendant of > Gtk.Widget.Gtk_Widget_Record. There is no lie: a Debug_Panel_Record IS A > Gtk_Widget_Record. The private view has more information: it actually IS > A Gtk_Scrolled_Window_Record, but the extra properties are not > accessible outside from the package body. > Ok. That's interesting. One more thing learned today :)
Le 09/04/2021 à 08:18, Dmitry A. Kazakov a écrit : > On 2021-04-09 07:28, DrPi wrote: >> Le 09/04/2021 à 00:27, Dmitry A. Kazakov a écrit : >>> On 2021-04-08 21:27, DrPi wrote: >>> >>>> I'm trying to create a GtkAda widget derived from a standard widget. >>>> >>>> -- debug_panel.ads >>>> with Gtk.Scrolled_Window; use Gtk.Scrolled_Window; >>>> with Gtk.Text_View; use Gtk.Text_View; >>>> >>>> package Debug_Panel is >>>> >>>> type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with >>>> private; >>>> type Debug_Panel is access all Debug_Panel_Record'Class; >>>> >>>> >>>> procedure Gtk_New (Panel : in out Debug_Panel); >>>> procedure Initialize (Panel : not null access >>>> Debug_Panel_Record'Class); >>>> >>>> private >>>> >>>> type Debug_Panel_Record is new Gtk_Scrolled_Window_Record with >>>> record >>>> Text : Gtk_Text_View; >>>> end record; >>>> >>>> end Debug_Panel; >>>> >>>> >>>> -- debug_panel.adb >>>> package body Debug_Panel is >>>> >>>> procedure Gtk_New (Panel : in out Debug_Panel) is >>>> begin >>>> Panel := new Debug_Panel_Record; >>>> Initialize (Panel); >>> >>> Debug_Panel.Initialize (Panel); >> I did try this notation and got this error : >> debug_panel.adb:6:07: invalid prefix in selected component "Debug_Panel" >> debug_panel.adb:6:18: prefixed call is only allowed for objects of a >> tagged type >> >> I've just realized this is because the package and the access type >> have the same name. > > You can disambiguate it so: > > Standard.Debug_Panel.Initialize (Panel) > > Standard.Debug_Panel - The package name > Standard.Debug_Panel.Debug_Panel - The type name > Ah. I have to remember this. That makes "Standard" some sort of reserved keyword. >>> Another way would be to remove "use Gtk.Scrolled_Window" and declare as >>> >>> type Debug_Panel_Record is >>> new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with private; >>> >>> Without "use" Initialize is unambiguous. >>> >> That makes sense. >> However, I don't understand why there is ambiguity when using "use". >> Debug_Panel (the type) is of type Debug_Panel_Record, so Initialize >> should resolve to the one using this type. Well, I guess I'm wrong. > > Debug_Panel belongs to both Debug_Panel_Record'Class and > Gtk_Scrolled_Window_Record'Class (and many other classes), so the > ambiguity. > Surprising behaviour for a strongly typed language but there surely is a good reason. >>> P.S. When you create new widget it is better to use a more general >>> ancestor hiding insufficient details, e.g. >>> >>> type Debug_Panel_Record is >>> new Gtk.Widget.Gtk_Widget_Record with private; >>> ... >>> private >>> type Debug_Panel_Record is >>> new Gtk.Scrolled_Window.Gtk_Scrolled_Window_Record with >>> record >>> ... >>> end record; >> >> I'm surprized this is possible to write such a thing in Ada. >> What does the compiler do with this ? > > The public view is Gtk_Widget_Record [with no record members], the full > view is Gtk_Scrolled_Window_Record [with record members you specified]. > Ok.
On 2021-04-09 13:42, DrPi wrote: > Le 09/04/2021 à 08:18, Dmitry A. Kazakov a écrit : >> Debug_Panel belongs to both Debug_Panel_Record'Class and >> Gtk_Scrolled_Window_Record'Class (and many other classes), so the >> ambiguity. >> > Surprising behaviour for a strongly typed language but there surely is a > good reason. It is strongly typed. The class is defined a set of types closed upon inheritance. When you declare a class-wide operation like Initialize it is meant to work on all instances of the class. There is no type violation or type coercion here. Initialize of Gtk_Scrolled_Window_Record'Class is defined on Gtk_Scrolled_Window_Record and all types derived from Gtk_Scrolled_Window_Record. When you declare another Initialize on Debug_Panel_Record'Class it is defined on Debug_Panel_Record and all its descendants. If you overload them, in a context you must disambiguate for Debug_Panel_Record and any descendant of. This is not different from Ada subtypes. For example, you can declare procedure Foo (I : Integer); and in some other package procedure Foo (I : Positive); If both become visible in a context you would have same problem. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
Le 09/04/2021 à 14:23, Dmitry A. Kazakov a écrit :
> On 2021-04-09 13:42, DrPi wrote:
>> Le 09/04/2021 à 08:18, Dmitry A. Kazakov a écrit :
>
>>> Debug_Panel belongs to both Debug_Panel_Record'Class and
>>> Gtk_Scrolled_Window_Record'Class (and many other classes), so the
>>> ambiguity.
>>>
>> Surprising behaviour for a strongly typed language but there surely is
>> a good reason.
>
> It is strongly typed.
>
> The class is defined a set of types closed upon inheritance. When you
> declare a class-wide operation like Initialize it is meant to work on
> all instances of the class. There is no type violation or type coercion
> here.
>
> Initialize of Gtk_Scrolled_Window_Record'Class is defined on
> Gtk_Scrolled_Window_Record and all types derived from
> Gtk_Scrolled_Window_Record.
>
> When you declare another Initialize on Debug_Panel_Record'Class it is
> defined on Debug_Panel_Record and all its descendants.
>
> If you overload them, in a context you must disambiguate for
> Debug_Panel_Record and any descendant of.
>
> This is not different from Ada subtypes. For example, you can declare
>
> procedure Foo (I : Integer);
>
> and in some other package
>
> procedure Foo (I : Positive);
>
> If both become visible in a context you would have same problem.
>
Ok.
Thanks for clarifying.