comp.lang.ada
 help / color / mirror / Atom feed
* access to subprogram disciminants
@ 1996-04-23  0:00 tmoran
  1996-04-24  0:00 ` Tucker Taft
  0 siblings, 1 reply; 8+ messages in thread
From: tmoran @ 1996-04-23  0:00 UTC (permalink / raw)


I want to declare an object with parameters, in particular, a
procedure parameter.  In Ada 83 I would have put the object in a
generic package and used the procedure as a parameter of the package.
In Ada 95 it appears I can make the object a record with a discriminant
of 'access to subprogram' type.  But when I try this, it always seems
to run into accessibility problems.
package definer is
  type a_s is access procedure(x:in out integer);
  type objects(s:a_s) is record ...
end definer;
with definer;
package user is
  procedure p(x:in out integer);
  object:objects(p'access);
..
1) How is this supposed to be done?
2) Other than generics or discriminants of records (or tasks),
what other ways are there of creating parameterized objects in Ada?




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
@ 1996-04-24  0:00 tmoran
  1996-04-25  0:00 ` Tucker Taft
  0 siblings, 1 reply; 8+ messages in thread
From: tmoran @ 1996-04-24  0:00 UTC (permalink / raw)


>I'm not sure what you are trying to accomplish, but the
>above is legal (modulo a few typos, etc.)
  Yes, I tried it again.  I had tried it the first time with
the "object:definer.objects(p'access);" in a main program "procedure"
rather than in a "package" and OS/2 GNAT complained about access level.
(Perils of trying to copy and simplify from actual code to internet post.)
I take it that merely means the outer main procedure has a lifetime
shorter than the packages it uses, so it must be structured to call on
a package to do the actual work.

>: 2) Other than generics or discriminants of records (or tasks),
>: what other ways are there of creating parameterized objects in Ada?
>
>Again, I am not exactly sure what you mean by "parameterized"
>objects.  It might be helpful to understand the ultimate problem

I have existing Ada 83 Windows code using generics in the form:

   procedure main_window_procedure(Message, ...

   package main_window is new Windows.frame_windows(
     width  =>200,
     height =>200,
     title  =>"Cars and Drivers",
     wndproc=>main_window_procedure);

   car_list:main_window.listboxes;
   driver_name_dialog:main_window.dialog_boxes;

   begin

   which_car:=main_window.open(car_list);

etc.

I think of 'main_window' as an object, parameterized by width, height,
title, wndproc, etc.  Though generics have several nice characteristics,
I can't easily make an array of them, for instance, so, now that
'access to subprogram' and 'access all' are available in Ada 95, it may
be reasonable to have instead

   type frame_windows(width, height: integer;
                      title: string_ptr;
                      wndproc: wndproc_ptr) is ...

   main_window:aliased frame_windows(
     width  =>200,
     height =>200,
     title  =>title_string_ptr,
     wndproc=>main_window_procedure'access);

   car_list:Windows.listboxes(main_window'access);
   driver_name_dialog:Windows.dialog_boxes(main_window'access);

   begin

   which_car:=Windows.open(car_list);

(Pardon typos and elisions.  This is typed for posting and is intended
to show the idea, not to be running code.)

That is what I mean by creating a parameterized object.  Unless I'm
missing something, or some clever way of using record tags, Ada 95
provides generics, records with discriminants, and tasks with
discriminants, as ways of declaring such things.  (Discounting
highly limited things like the size of an array as a 'parameter'
of the array)




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
  1996-04-23  0:00 tmoran
@ 1996-04-24  0:00 ` Tucker Taft
  0 siblings, 0 replies; 8+ messages in thread
From: Tucker Taft @ 1996-04-24  0:00 UTC (permalink / raw)


tmoran@bix.com wrote:
: I want to declare an object with parameters, in particular, a
: procedure parameter.  In Ada 83 I would have put the object in a
: generic package and used the procedure as a parameter of the package.
: In Ada 95 it appears I can make the object a record with a discriminant
: of 'access to subprogram' type.  But when I try this, it always seems
: to run into accessibility problems.

You example, after filling in the "..." with something reasonable,
compiles fine for me.  What is the "accessibility" problem you
are having?  Are you trying to use a nested procecedure?

: package definer is
:   type a_s is access procedure(x:in out integer);
:   type objects(s:a_s) is record ...
: end definer;
: with definer;
: package user is
:   procedure p(x:in out integer);
:   object:objects(p'access);
          ^^ "definer."
: ..

: 1) How is this supposed to be done?

I'm not sure what you are trying to accomplish, but the
above is legal (modulo a few typos, etc.)

: 2) Other than generics or discriminants of records (or tasks),
: what other ways are there of creating parameterized objects in Ada?

Again, I am not exactly sure what you mean by "parameterized" 
objects.  It might be helpful to understand the ultimate problem
you are trying to solve.  The specific solution you have sketched
out doesn't explain what is the underlying task to be solved.

-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Cambridge, MA  USA




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
  1996-04-24  0:00 access to subprogram disciminants tmoran
@ 1996-04-25  0:00 ` Tucker Taft
  0 siblings, 0 replies; 8+ messages in thread
From: Tucker Taft @ 1996-04-25  0:00 UTC (permalink / raw)


tmoran@bix.com wrote:

: ...
: >: 2) Other than generics or discriminants of records (or tasks),
: >: what other ways are there of creating parameterized objects in Ada?
: >
: >Again, I am not exactly sure what you mean by "parameterized"
: >objects.  It might be helpful to understand the ultimate problem

: I have existing Ada 83 Windows code using generics in the form:

:    procedure main_window_procedure(Message, ...

:    package main_window is new Windows.frame_windows(
:      width  =>200,
:      height =>200,
:      title  =>"Cars and Drivers",
:      wndproc=>main_window_procedure);

:    car_list:main_window.listboxes;
:    driver_name_dialog:main_window.dialog_boxes;

:    begin

:    which_car:=main_window.open(car_list);

: etc.

: I think of 'main_window' as an object, parameterized by width, height,
: title, wndproc, etc.  Though generics have several nice characteristics,
: I can't easily make an array of them, for instance, so, now that
: 'access to subprogram' and 'access all' are available in Ada 95, it may
: be reasonable to have instead

:    type frame_windows(width, height: integer;
:                       title: string_ptr;
:                       wndproc: wndproc_ptr) is ...

:    main_window:aliased frame_windows(
:      width  =>200,
:      height =>200,
:      title  =>title_string_ptr,
:      wndproc=>main_window_procedure'access);

:    car_list:Windows.listboxes(main_window'access);
:    driver_name_dialog:Windows.dialog_boxes(main_window'access);

:    begin

:    which_car:=Windows.open(car_list);

: (Pardon typos and elisions.  This is typed for posting and is intended
: to show the idea, not to be running code.)

: That is what I mean by creating a parameterized object.  Unless I'm
: missing something, or some clever way of using record tags, Ada 95
: provides generics, records with discriminants, and tasks with
: discriminants, as ways of declaring such things.  (Discounting
: highly limited things like the size of an array as a 'parameter'
: of the array)

I think you are perhaps being misled by the RM's use of the 
term "parameterized" in association with type discriminants.  

What you are trying to accomplish can be done using normal record 
*components*, initialized as a result of calling a function
or procedure.  In other OOP's, such a function would often be called
a "constructor," but in Ada, you can just use normal functions or
procedures as "constructors."  

Don't try to make all of these "parameters" into discriminants.  
Just declare them as components of the data type.  Then, a user would
declare a simple "Frame_Window" or whatever, and initialize it from the
result of a function call, or by a subsequent procedure call.
The parameters to this initializing function/procedure are the
"parameters" you are probably interested in.  

This approach is much more flexible, as you can have multiple
constructor subprograms, taking different combinations of parameters.
If you are doing a GUI, chances are that you will be using access
types for representing these GUI elements, so it might be more
natural and efficient to make your constructor "functions"
return an access value, rather than a record object.
An additional advantage is that you can make the entire type
private, and choose to represent the information in various
ways.  If you make all the "parameters" into discriminants, then
they are always visible to all clients, and you are forced to represent
them explicitly, rather than perhaps implicitly in some other
part of the data type.

-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Cambridge, MA  USA




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
  1996-04-26  0:00 tmoran
  1996-04-26  0:00 ` Robert I. Eachus
@ 1996-04-26  0:00 ` Tucker Taft
  1 sibling, 0 replies; 8+ messages in thread
From: Tucker Taft @ 1996-04-26  0:00 UTC (permalink / raw)



tmoran@bix.com wrote:

: >What you are trying to accomplish can be done using normal record
: >*components*, initialized as a result of calling a function
: >or procedure.  In other OOP's, such a function would often be called
: >a "constructor," but in Ada, you can just use normal functions or
: >procedures as "constructors."

:   I had thought that 'constructor' in C++ was close to 'procedure
: initialize' for an Ada 95 Controlled type.  

Not really.  The procedure Initialize of a controlled type is
for *default* initialization, roughly equivalent to a parameterless
constructor for C++.  Constructor's with parameters are a better 
match for a parameterized Ada function the returns an initialized 
object, or a pointer to a newly allocated and initialized object.

: ... I also thought that the
: only parameters available to procedure 'initialize' were discriminants
: or other members of the record structure being initialized.  Further,
: the compiler will insist that values be supplied for (non-default
: valued) discriminants, whereas I can't get the compiler to enforce a
: requirement for *any* values for the rest of the record components.
: Am I mistaken?

If the type is private, then the user will have to call one of
your subprograms to initialize an object.  Such subprograms
can have parameters, with or without defaults.

If the type is also declared with "unknown" discriminants,
such as:
    type T(<>) is private;

then the user cannot declare a default-initialized object, but rather
must call one of your functions to specify the initial value.

: ...
:   I try to think of an Ada compiler not just as a tool to do scut work
: like converting code in an HLL to binary, but as a somewhat intelligent
: helper guiding me away from error.  Sort of like the difference between
: a rod and hangers keeping my clothes off the floor, vs a gentleman's
: valet suggesting that a particular tie might not be the best choice
: with a particular suit.  So I'm trying to arrange things so the
: language and compiler will be as helpful as possible.

I certainly sympathize with your goal of using the compiler to
help as much as possible.  However, I don't think discriminants
are the most appropriate way to accomplish this particular
kind of parameterization.  Functions with parameters are much
more flexible, and if used appropriately, more efficient.

-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Cambridge, MA  USA




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
  1996-04-26  0:00 tmoran
@ 1996-04-26  0:00 ` Robert I. Eachus
  1996-04-26  0:00 ` Tucker Taft
  1 sibling, 0 replies; 8+ messages in thread
From: Robert I. Eachus @ 1996-04-26  0:00 UTC (permalink / raw)



In article <4lp3sc$glg@news1.delphi.com> tmoran@bix.com writes:

 >    I had thought that 'constructor' in C++ was close to 'procedure
 > initialize' for an Ada 95 Controlled type.  I also thought that the
 > only parameters available to procedure 'initialize' were discriminants
 > or other members of the record structure being initialized.  Further,
 > the compiler will insist that values be supplied for (non-default
 > valued) discriminants, whereas I can't get the compiler to enforce a
 > requirement for *any* values for the rest of the record components.
 > Am I mistaken?

   Yes.  If a record component has a default initial value, you can
never create a record object where it's value is undefined.

   If you want to change a record discriminant, you are required to
assign an aggregate value so that any components which depend on the
discriminant have valid values.  This is nice for preserving the
principle above, but makes changing discriminants that do not
determine the other record components a lot more error prone.

   (Notice that it is possible in Ada to have discriminants on
subcomponents which are records that are not discriminants of the
parent type, and in fact the parent type may have no discriminants.
Take advantage of this to keep necessary discriminants as closely to
the components they control as you can.)

  > >Don't try to make all of these "parameters" into discriminants.
  > >Just declare them as components of the data type.  Then, a user would
  > >declare a simple "Frame_Window" or whatever, and initialize it from the
  > >result of a function call, or by a subsequent procedure call.
  >   But that function or procedure call might be left out, causing
  > a run time error.

   Yep, could be.  If you are that paranoid--and sometimes it is
correct to be--what I usually do is define a default initial value
that raises an exception.  Do it right, and your compiler will tell
you about it for every object which does not explicitly call an
constructor.

   type T is record...

     S: String(1..4) := (-3..0 => ' ');
   end record;

  >   I try to think of an Ada compiler not just as a tool to do scut
  > work like converting code in an HLL to binary, but as a somewhat
  > intelligent helper guiding me away from error.  Sort of like the
  > difference between a rod and hangers keeping my clothes off the
  > floor, vs a gentleman's valet suggesting that a particular tie
  > might not be the best choice with a particular suit.  So I'm
  > trying to arrange things so the language and compiler will be as
  > helpful as possible.

    I try to do the same, but you have to be willing to listen to the
valet.  Get a compiler that issues good warning messages and never
turn them off.

    I had an example yesterday.  Recompiled some (GNAT compiled) code
that looked to be pure Ada 83 in VADS and got two warning messages.
Looked at the source and realized that Ada 83 did not allow sliding in
that context.  Modified the code and everything worked when finally
executed.  Much better than using the debugger.
--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
@ 1996-04-26  0:00 tmoran
  1996-04-26  0:00 ` Robert I. Eachus
  1996-04-26  0:00 ` Tucker Taft
  0 siblings, 2 replies; 8+ messages in thread
From: tmoran @ 1996-04-26  0:00 UTC (permalink / raw)


You asked for the underlying reason and I answered in terms of
code, but I should have said more basically "to move errors from
run time to compile time".    e.g.
  main_window, go_button:HANDLE;
  ...
  go_button:=CreateWindow("button", ... , main_window, ... );
allows one to write code creating a button before creating its
parent window, causing a run time error.  But
  main_window:aliased frame_windows(initial_width=> ...
  go_button:buttons(parent=>main_window'access, ...
where 'frame_windows' is a controlled type whose initialization
procedure creates a window, eliminates the possibility of that
run time error.  If the coder declares go_button before declaring
main_window, the compiler will point out the error.

>What you are trying to accomplish can be done using normal record
>*components*, initialized as a result of calling a function
>or procedure.  In other OOP's, such a function would often be called
>a "constructor," but in Ada, you can just use normal functions or
>procedures as "constructors."

  I had thought that 'constructor' in C++ was close to 'procedure
initialize' for an Ada 95 Controlled type.  I also thought that the
only parameters available to procedure 'initialize' were discriminants
or other members of the record structure being initialized.  Further,
the compiler will insist that values be supplied for (non-default
valued) discriminants, whereas I can't get the compiler to enforce a
requirement for *any* values for the rest of the record components.
Am I mistaken?

>Don't try to make all of these "parameters" into discriminants.
>Just declare them as components of the data type.  Then, a user would
>declare a simple "Frame_Window" or whatever, and initialize it from the
>result of a function call, or by a subsequent procedure call.
  But that function or procedure call might be left out, causing
a run time error.

>If you make all the "parameters" into discriminants, then
>they are always visible to all clients, and you are forced to represent
>them explicitly, rather than perhaps implicitly in some other
>part of the data type.

  If 'frame_windows' is limited then main_window.initial_width, et al,
are read only constants, no?  Since the width of a window may well
change, the current width is clearly stored elsewhere, accessible only
by calling a function
  w:=current_width(main_window);
Hopefully someone coding
  w:=main_window.initial_width;
will realize they are getting the initial, not the current, width.

  I try to think of an Ada compiler not just as a tool to do scut work
like converting code in an HLL to binary, but as a somewhat intelligent
helper guiding me away from error.  Sort of like the difference between
a rod and hangers keeping my clothes off the floor, vs a gentleman's
valet suggesting that a particular tie might not be the best choice
with a particular suit.  So I'm trying to arrange things so the
language and compiler will be as helpful as possible.




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: access to subprogram disciminants
@ 1996-04-27  0:00 tmoran
  0 siblings, 0 replies; 8+ messages in thread
From: tmoran @ 1996-04-27  0:00 UTC (permalink / raw)



  main_window : frame_windows ...
  car_list : listboxes(main_window'access, ...

The problem is that I want to make sure that CreateWindow has been
called for main_window before car_list is used, and I want a
compilation error if that isn't the case.  The only way I can see to
accomplish that is to make the declaration of main_window somehow
call CreateWindow.  That could be done either with an initialization
procedure, or by forcing the user to call a function assigning a
value:

  main_window : frame_windows:=create(various parameters);

But the function option is not available if frame_windows is limited.

So I'm back to a 'procedure initialize' which calls CreateWindow.
Now it could make that call with default values for position, size,
title, wndproc, and everything else and expect the user to make a
later procedure call or calls to change those to real values, or it
could get their values from discriminants 'initial_width,
initial_title' etc.  (Some of which can have default values, of
course.)  The latter seems simpler to me.

    I admit here to a personal preference for stack order rather
than heap order creation/destruction of things unless lifetime
requirements or something really require random heap order.  It
tends to keep things more orderly and in this case, given that a
window can be minimized or hidden, it doesn't seem to prevent any
needed flexibility.  Putting the CreateWindow call in the
declarations, rather than some arbitrary place in the sequence of
statements, fits that policy even if there were no listboxes etc.




^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~1996-04-27  0:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-04-24  0:00 access to subprogram disciminants tmoran
1996-04-25  0:00 ` Tucker Taft
  -- strict thread matches above, loose matches on Subject: below --
1996-04-27  0:00 tmoran
1996-04-26  0:00 tmoran
1996-04-26  0:00 ` Robert I. Eachus
1996-04-26  0:00 ` Tucker Taft
1996-04-23  0:00 tmoran
1996-04-24  0:00 ` Tucker Taft

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