comp.lang.ada
 help / color / mirror / Atom feed
* ForTran-Ada + flamette + question
@ 1986-05-21  6:06 larry
  1986-05-21 15:41 ` Mark Biggar
                   ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: larry @ 1986-05-21  6:06 UTC (permalink / raw)


>  I for one am getting a little tired of short, nasty, replies from 
>  "real-annoyed-sender"s who pull the reply trigger before they stop....

Me too.

The biggest difference is that you can use subprogram names as parameters 
to subprograms in ForTran and you can't in Ada.  This is causing me major
problems in porting EMACS (written in C) to Ada.  An important feature of 
EMACS is the ability to do run-time rebinding of functions to key-strokes
and I haven't figured out how to do this in Ada.

In C one can build an array of records, each record containing a pointer 
to a function and the string of characters used to invoke the function.  
When that string is intercepted from the keyboard, the matching function
is invoked.

With this to build on it's fairly easy to create a macro facility, and even 
a subset programming language so that users can extend the editor command 
set.

Anyone have an idea how to do run-time binding of keys to commands in Ada?

                                                    Larry @ jpl-vlsi.arpa

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

* Re: ForTran-Ada + flamette + question
  1986-05-21  6:06 larry
@ 1986-05-21 15:41 ` Mark Biggar
  1986-05-21 16:40 ` broman
  1986-05-28 19:30 ` David Lamb
  2 siblings, 0 replies; 23+ messages in thread
From: Mark Biggar @ 1986-05-21 15:41 UTC (permalink / raw)


In article <8605210805.AA20308@ucbvax.Berkeley.EDU> larry@JPL-VLSI.ARPA writes:
>Anyone have an idea how to do run-time binding of keys to commands in Ada?

This problem has a simple solution.

There are two types of function in something like EMACS that you want to
be able to bind to a key (or key sequence):  built-in functions and
user-defined functions (usually written in a lisp like language).

Now if you assign to each function an id code (e.g. negative numbers for
built-in functions and positive numbers for user-defined) then bind the
key sequence to the id code.

To interpret the key sequence just look at the id code, if it denotes a
built-in you select the code for the built-in using a humongous case
statement; otherwise pass the id code for the user-defined function
off to the interpreter.  Note that the same id codes for the built-in
functions can be used in the data structures that are used to build
the user-defined functions (you have the same problem with binding built-in
functions into the user-defined functions as you do with binding them to
key sequences).

Mark Biggar
{allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb

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

* Re: ForTran-Ada + flamette + question
  1986-05-21  6:06 larry
  1986-05-21 15:41 ` Mark Biggar
@ 1986-05-21 16:40 ` broman
  1986-05-28 19:30 ` David Lamb
  2 siblings, 0 replies; 23+ messages in thread
From: broman @ 1986-05-21 16:40 UTC (permalink / raw)


In article <8605210805.AA20308@ucbvax.Berkeley.EDU>, larry@JPL-VLSI.ARPA writes:
> The biggest difference is that you can use subprogram names as parameters 
> to subprograms in ForTran and you can't in Ada.  This is causing me major
> problems in porting EMACS (written in C) to Ada.
> Anyone have an idea how to do run-time binding of keys to commands in Ada?

Unfortunately, Ada seems to be designed to make that as hard as possible.
The Steelman requirement 5D says: "Procedures, functions, types, labels,
exception situations, and statements shall not be assignable to variables,
be computable as values of expressions, or be usable as nongeneric parameters
to procedures or functions."  This is a major lossage, in my view, compared
to the reasonable design in (e.g.) Modula-2 for defining procedure pointers.

The only way I can see to simulate procedure pointers is to define an
enumeration type with elements corresponding to the procedures that may be
pointed to (as well as NULL) and write a procedure with a big CASE
statement which dispatches to the procedure corresponding to the
enumeration-value you supply as a parameter (or complains about calling NULL).

Yeah, I know, yuk.


Vincent Broman, code 632,  Naval Ocean Systems Center, San Diego, CA 92152, USA
Phone: +1 619 225 2365        {seismo,caip,ihnp4,ucbvax}!\\\\\\\
Arpa: broman@bugs.nosc.mil Uucp: {floyd,moss,bang,hp-sdd,sdcsvax}!noscvax!broman

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

* ForTran-Ada + flamette + question
       [not found] <175155@QZCOM>
@ 1986-05-22  1:00 ` Jan_Michael_Rynning
  0 siblings, 0 replies; 23+ messages in thread
From: Jan_Michael_Rynning @ 1986-05-22  1:00 UTC (permalink / raw)


AMIS (an Ersatz EMACS written in PASCAL, and running on VMS,
TOPS-10, RSTS/E, PRIMOS, and SINTRAN III), does it like this:

CASE value OF
1: function_1(with_appropriate_arguments);
2: function_2(with_appropriate_arguments);
...
END;

Though this is a bit clumsy, I guess you could use the same
solution for ADA. Instead of rebinding the function itself,
you rebind the corresponding number. You should, of course,
use symbolic names instead of numbers.

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

* Re: ForTran-Ada + flamette + question
@ 1986-05-28 15:54 richw
  1986-05-30 12:46 ` Russ Holden
  0 siblings, 1 reply; 23+ messages in thread
From: richw @ 1986-05-28 15:54 UTC (permalink / raw)



The following includes a suggestion for solving your problem, along
with my own defense of the decision to omit procedure-pointers from Ada:

The first solution I can think of (and, I guess, the simplest?) would
be to define an enumeration type, where each enumeral (is that a
word?) corresponds to one of the functions you'd like to bind to a
key-sequence.  Then just write a procedure that takes such an enumeral
as an "in" parameter and then "case"s on that parameter to the
appropriate call.

Abstractly, this new function is similar to "eval" in Lisp.  Now, instead
of binding characters sequences to function-pointers (as in C), just bind
the character sequences to enumerals.

Other comments about why I think the ability to pass procedures around
was omitted from Ada: (note that these are just opinions -- I'm not
quoting one of the design documents for Ada or anything like that)

In a language like Lisp, you can actually create procedures AT RUN-TIME
since they're just lists (i.e. data).  However, in C and Ada this isn't
true.  In C, all procedures that you can point to at run-time are defined
at compile time.  I think this last fact is an important one to consider;
the above method of mapping enumerals to subprogram calls works for Ada.
It wouldn't work in Lisp because you can't list all of the subprograms
that will exist when you run the program BEFORE you run it (because you
can build Lisp procedures "on the fly"); thus, you can't define an
enumeration type since that type has a finite number of compile-time
enumerals.

Anyway, my point is that I think that one can do all that you can do in
C in Ada by using the above enumerals-to-subprogram mapping method; I'd
be interested if people can provide counter-examples (I realize that
you'd have to do more if the procedures you call take different numbers
of arguments, but then again, you'd have to be more fancy in C, too).

If so, then omitting the ability to pass procedures around in Ada saved
the language designers from adding more syntactic and semantic and
run-time constructs to the language to support this.  Considering
the fact that Ada is already big, I think this was a wise decision --
especially since, with a minimal amount of work, you CAN do what you
want (using the enumeral-to-subprogram method).

Think about it -- strict type-checking becomes much more messy...
It is possible to add this to your language (e.g. CLU), but I personally
don't think it's worth complicating your language.  Even though C lets
you do it, C BY NO MEANS does type-checking of calls to procedures which
were passed in as arguments (it doesn't even check that the number of
arguments is correct).  Yes, C is an "unsafe" language...

Comments?  Remember, these are casual remarks and opinions -- please
think before you flame  :-)

Rich

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

* Re: ForTran-Ada + flamette + question
@ 1986-05-28 16:56 richw
  1986-05-30 16:28 ` Vincent P. Broman
  0 siblings, 1 reply; 23+ messages in thread
From: richw @ 1986-05-28 16:56 UTC (permalink / raw)



> Unfortunately, Ada seems to be designed to make that as hard
> as possible.
>        :
> The only way I can see to simulate procedure pointers is to
> define an enumeration type with elements corresponding to
> the procedures that may be pointed to...

I personally don't think this is so bad or "hard".  In any case,
read on...

> The Steelman requirement 5D says: "Procedures, functions, types,
> labels, exception situations, and statements shall not be
> assignable to variables, be computable as values of expressions,
> or be usable as nongeneric parameters to procedures or
> functions."  This is a major lossage, in my view, compared to
> the reasonable design in (e.g.) Modula-2 for defining procedure
> pointers.

The most common complaint about Ada is that it's too large -- you're
suggesting that they should've added more?  Even though it really
isn't that hard to do what you want without this feature?  In my own
experience with CLU and C, both of which allow procedures as arguments,
the feature just wasn't used all that much to justify its existence...

In any case, you have overlooked the fact that Ada provides generics
which, although it can't be used for this particular case because generic
instantiation happens at compile time, can often be used where one would
like to define a subprogram which takes a subprogram as a argument...

It would've been REAL nice if they added Smalltalk-like inheritance to
Ada, too.  What about type inference?  Or logic programming features
like Prolog?  Or the ability to create functions at run-time like in
Lisp (which is pretty much what you want for this application)?

You've gotta draw the line somewhere.  I'm continually amazed how
people complain that Ada has either too much or not enough because
it's left out their favorite feature from language X.  Considering the
design goals for Ada, I think they did a good (not perfect) job of
designing a language with which you can write both efficient and
abstract, safe programs.

> Vincent Broman, code 632,  Naval Ocean Systems Center, San Diego, CA 92152, USA
> Phone: +1 619 225 2365        {seismo,caip,ihnp4,ucbvax}!\\\\\\\
> Arpa: broman@bugs.nosc.mil Uucp: {floyd,moss,bang,hp-sdd,sdcsvax}!noscvax!broman

Rich Wagner

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

* Re: ForTran-Ada + flamette + question
  1986-05-21  6:06 larry
  1986-05-21 15:41 ` Mark Biggar
  1986-05-21 16:40 ` broman
@ 1986-05-28 19:30 ` David Lamb
  2 siblings, 0 replies; 23+ messages in thread
From: David Lamb @ 1986-05-28 19:30 UTC (permalink / raw)


Someone recently asked if there was any way to pass procedures as
parameters in Ada, or place them in records;  I think the problem in
question was doing key-to-procedure bindings in an editor.  Ada has
neither of these directly;  you can sometimes simulate them in ugly
ways.  You can simulate procedure parameters via generics: pass the
procedures or functions as generic parameters, and hope your compiler
is smart enough to pass them as procedures at runtime.  You can get
procedure variables (or record fields) with the tasking mechanism
(yech!) as shown in "Simulating Procedure Variables with Ada Tasks",
D.A. Lamb and P. Hilfinger, IEEE Trans. Soft. Eng.  v9#1 (Jan 83).

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

* Re: ForTran-Ada + flamette + question
  1986-05-28 15:54 ForTran-Ada + flamette + question richw
@ 1986-05-30 12:46 ` Russ Holden
  1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
                     ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Russ Holden @ 1986-05-30 12:46 UTC (permalink / raw)


> 
> The following includes a suggestion for solving your problem, along
> with my own defense of the decision to omit procedure-pointers from Ada:
> 
> The first solution I can think of (and, I guess, the simplest?) would
> be to define an enumeration type, where each enumeral (is that a
> word?) corresponds to one of the functions you'd like to bind to a
> key-sequence.  Then just write a procedure that takes such an enumeral
> as an "in" parameter and then "case"s on that parameter to the
> appropriate call.
>
> Anyway, my point is that I think that one can do all that you can do in
> C in Ada by using the above enumerals-to-subprogram mapping method; I'd
> be interested if people can provide counter-examples (I realize that
> you'd have to do more if the procedures you call take different numbers
> of arguments, but then again, you'd have to be more fancy in C, too).


Rich, you are missing out on the beauty of procedure passing.  Simply put
it gives you the ability to dynamically bind actions without the invoker
of the procedure having to know about the procedure being called.  A 
couple of examples are:

1) Table-driven code - Using C all you have to do is add a procedure
   to a table.  Using the ADA enumerated-to-procedure mapping code
   modifications are involved (see below).

2) It provides the ability for higher levels of software to abstract
   procedures from lower levels such that lower levels call but do
   not "use" these procedures (in Parnas terminology).  For example,
   (and this is not hypothetical) is a DBMS which wants to perform
   qualification of records against user-specified predicates before
   retreiving them (copying them off their page essentially).  Since
   the code performing page level manipulations is generally at a much
   lower level in processing than the code which understands about
   the values in records a procedure made available to the page level
   is an appropriate mechanism.  The use of enumerated types does no
   good and there are no real good solutions that I know of in ADA
   (if anyone has any please send me mail).

   I have used procedure pointers in lots of other situations where
   a high-level wants or needs to provide a service to a lower level.
   The only requirement is that a "standard" invokation mechanism be
   defined.
-- 
Russell Holden
Computer Corporation of America
Four Cambridge Center
Cambridge, MA 02142

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

* Re: ForTran-Ada + flamette + question
  1986-05-28 16:56 ForTran-Ada + flamette + question richw
@ 1986-05-30 16:28 ` Vincent P. Broman
  1986-06-02 16:28   ` Jonathan P. Biggar
  1986-06-04 23:39   ` Bryce Bardin
  0 siblings, 2 replies; 23+ messages in thread
From: Vincent P. Broman @ 1986-05-30 16:28 UTC (permalink / raw)


<>

richw@ada-uts justifies the lack of procedure pointers in ada by
asserting that they can be simulated satisfactorily with an 'eval'
procedure, that dispatches on a parameter of an enumerated type by
invoking the procedure that is logically associated with the
parameter's value.

This is insufficient. The canonical example is a numerical quadrature
package which integrates user-supplied functions.  The problem is that
the dispatcher that repeatedly invokes the integrand must know the NAMES
of all potential integrands in order to invoke them.  These names are
known only at user-compile-time, not library-compile-time.
The quadrature routine should not see integrand names, it should only
specify the parameter and result types of the eventual integrands.

A generic quadrature package mispleases because separate copies of
it must be instantiated for each function to be integrated.

I have used function/procedure pointers in Algol-family languages
fairly often.  A big attraction (to me :-) of Scheme and its cousins is
the power afforded by making procedures first-class objects.  If
language size is the real concern here, I would gladly give up in
return such dubious features of ada as: default values of parameters,
the raise statement, assignments to objects of unconstrained size,
etc.


Vincent Broman, code 632,  Naval Ocean Systems Center, San Diego, CA 92152, USA
Phone: +1 619 225 2365        {seismo,caip,ihnp4,ucbvax}!\\\\\\\
Arpa: broman@bugs.nosc.mil Uucp: {floyd,moss,bang,hp-sdd,sdcsvax}!noscvax!broman

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

* Re: ForTran-Ada + flamette + question
  1986-05-30 16:28 ` Vincent P. Broman
@ 1986-06-02 16:28   ` Jonathan P. Biggar
  1986-06-03  5:11     ` Barry Margolin
  1986-06-03 12:39     ` Russ Holden
  1986-06-04 23:39   ` Bryce Bardin
  1 sibling, 2 replies; 23+ messages in thread
From: Jonathan P. Biggar @ 1986-06-02 16:28 UTC (permalink / raw)


In article <503@noscvax.UUCP> broman@noscvax.UUCP (Vincent P. Broman) writes:
>A generic quadrature package mispleases because separate copies of
>it must be instantiated for each function to be integrated.

Please DON'T confuse Ada with its current implementations.  There is
no reason that the bodies of a generic quadrature package cannot be
shared.  Just because current implementations don't do it (YET!!!),
don't damn Ada.


Jonathan Biggar (sdcrdcf!jonab)

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

* Re: ForTran-Ada + flamette + question
  1986-06-02 16:28   ` Jonathan P. Biggar
@ 1986-06-03  5:11     ` Barry Margolin
  1986-06-03 12:39     ` Russ Holden
  1 sibling, 0 replies; 23+ messages in thread
From: Barry Margolin @ 1986-06-03  5:11 UTC (permalink / raw)


In article <230@sdcjove.UUCP> jonab@phoebe.UUCP (Jonathan P. Biggar) writes:
>Please DON'T confuse Ada with its current implementations.  There is
>no reason that the bodies of a generic quadrature package cannot be
>shared.  Just because current implementations don't do it (YET!!!),
>don't damn Ada.

A language is only as good as its implementations.  If no existing Ada
compilers produce shared code from generic procedures, my first guess is
because it is hard to implement.  If it is going to be several years
before we have smart enough implementations, that means that for several
years Ada programmers will not be able to use this feature as
extensively as they would like.  Theoretical compilers are only useful
for producing theoretical code.  Most customers want real code.

While the language Ada isn't totally to blame, it is one of the
culprits, because it is so complex that it is hard to implement well,
even given three decades of compiler implementation technology.  It's
hard not to confuse a language with its implementations; the only metric
one has is existing generated object code.
-- 
    Barry Margolin
    ARPA: barmar@MIT-Multics
    UUCP: ..!genrad!mit-eddie!barmar

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

* Re: ForTran-Ada + flamette + question
  1986-06-02 16:28   ` Jonathan P. Biggar
  1986-06-03  5:11     ` Barry Margolin
@ 1986-06-03 12:39     ` Russ Holden
  1 sibling, 0 replies; 23+ messages in thread
From: Russ Holden @ 1986-06-03 12:39 UTC (permalink / raw)


> In article <503@noscvax.UUCP> broman@noscvax.UUCP (Vincent P. Broman) writes:
> >A generic quadrature package mispleases because separate copies of
> >it must be instantiated for each function to be integrated.
> 
> Please DON'T confuse Ada with its current implementations.  There is
> no reason that the bodies of a generic quadrature package cannot be
> shared.  Just because current implementations don't do it (YET!!!),
> don't damn Ada.
> 

Right, don't damn Ada for silly things when there are so many real
reasons to do so!

-- 
Russell Holden
Computer Corporation of America
Four Cambridge Center
Cambridge, MA 02142

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

* Re: ForTran-Ada + flamette + question
  1986-05-30 16:28 ` Vincent P. Broman
  1986-06-02 16:28   ` Jonathan P. Biggar
@ 1986-06-04 23:39   ` Bryce Bardin
  1 sibling, 0 replies; 23+ messages in thread
From: Bryce Bardin @ 1986-06-04 23:39 UTC (permalink / raw)


The discussion of whether Ada should support procedures as variables and
parameters seems to be a miscommunication, at least in part.  Some people
say that Ada can't support the concept well enough to be useful and that
they can't live without the feature.  Others argue that Ada doesn't need
the feature.  Still others point to the Steelman requirements that ruled
it out.  I would like to address the following points:
	(1) Does Ada support procedures as variables, and
	(2) Does it support it well enough?

Firstly, Ada has a consistent model of static (compile/link-time)
checkable semantics based on the concept of strong typing.  This is 
supplemented by run-time checking to assure that values do not go outside
their defined ranges.  (High-quality implementations are able to remove most
of these checks by analyzing the code carefully.)

The purpose of these concepts is to assure that with reasonable care, robust
programs can be written.  Ada deliberately seeks to minimize the risks of 
writing incorrect code, although it cannot provide absolute protection, of 
course, and it does not prevent incorrect usage of the facilities it provides.

Within the Ada model there are two options, both of which allow Ada to 
provide safety:  using a case statement on an enumeration type and 
instantiating a generic unit which has a generic formal subprogram 
parameter.  Both of these mechanisms are simple and straightforward to use
in the case of static binding, and both can be implemented efficiently.

(Those of you who object on aesthetic grounds to these techniques simply do
not yet appreciate the value of strong typing.  You can only be
convinced by being condemned to manage the implementation of a 250,000
line system in FORTRAN, Pascal, or (better yet) in C and then being allowed
to re-implement it in Ada, for comparison.)

Secondly, Ada has mechanisms for escape from the strict strong-typing
semantics.  In particular, there are Unchecked_Conversion, address clauses,
and pragma Interface.  Implementations exist with all of these features 
(and you who wish to live dangerously, i.e., to indulge in weakly-typed
programming, should insist that your favorite Ada compiler support them
properly).  With a simple C or assembly language routine or two, you too
can execute data in Ada!  All kidding aside, it is clear that for those
who want to do run-time binding of procedures, this is a legitimate approach
which should meet your immediate needs.  Roughly, all you have to do is to
load the code to be executed into a data object, figure out where its entry
is, add the appropriate offset to the address of the data object (performing
appropriate (unchecked) conversions along the way, and pass the resulting
value to the (non-Ada) module which you have imported into the Ada program
using pragma Interface for it to execute.  Of course, there are a couple of
drawbacks:  you can hang yourself and it ain't portable!  (So what's new!)

With regard to the second question, it is mainly a philosophical issue.

Should Ada have an implementation-independent means within the language 
which directly supports executing procedure variables which are statically 
checkable?  (I mean to imply here that appropriate run-time checks (which the
compiler can optimize away) would be performed to assure that the parameter 
and result type profiles of the procedure (or function) value match the call
which is made.)  I would answer yes.

What if the binding were dynamic?  (I assume no run-time checks here.)
I would again answer yes, provided that the syntax made it clear that the
model was being violated, as it currently does with Unchecked_Conversion and
pragma Inline.

I have spoken.

(Honesty compels me to admit, however, that the DoD has the last word.)


Cheers
-------

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

* Re: ForTran-Ada + flamette + questi
  1986-05-30 12:46 ` Russ Holden
@ 1986-06-20 15:36   ` richw
  1986-06-22  3:00     ` Russ Holden
                       ` (2 more replies)
  1986-07-14 17:01   ` ForTran-Ada + flamette + questi richw
  1986-07-22 12:59   ` stt
  2 siblings, 3 replies; 23+ messages in thread
From: richw @ 1986-06-20 15:36 UTC (permalink / raw)



>>  ***** ada-uts:net.lang.ada / cca.UUCP!holden /  8:46 am  May 30, 1986
>>  Rich, you are missing out on the beauty of procedure passing.
>>  (Russell Holden)

Pardon me, but...
I've actually used this feature in many languages: Lisp, CLU, C, and
Smalltalk.  As a matter of fact, I'm in the process of rewriting a
C program (which used pointers to functions) in Ada.

>>  Simply put it gives you the ability to dynamically bind actions
>>  without the invoker of the procedure having to know about the
>>  procedure being called.

So does the enumeration-to-procedure mapping method I proposed.

>>                         ...  The use of enumerated types does no
>>  good and there are no real good solutions that I know of in ADA

I'm sorry, but I simply fail to see how your examples provide
conclusive arguments that this method will not work in general.
GRANTED, the mapping method is less convenient for the programmer,
but my point was that it is nevertheless possible in Ada at a
reasonable expense (which I think is justifiable given that omitting
procedure pointers from Ada prevented Ada from becoming even more
complex).

To be more concrete, the following outlines a package spec which
one could use:

    package Mapper is

          type No_Argument_Procedure_Pointer is (
              proc_A_0, proc_B_0, ... );

          type One_Integer_Argument_Procedure_Pointer is (
              proc_A_1_int, proc_B_1_int, ... );
                   :

          procedure Call (
              p : in No_Argument_Procedure_Pointer );

          procedure Call (
              p : in One_Integer_Argument_Procedure_Pointer;
              i : in Integer );
                   :
    end Mapper

The implementation of each "Call" procedure would simply be a case
statement to the appropriate "real" procedure call.

If anyone could provide an example where a Procedure_Pointer could
not be used wherever one would like to use a "real" pointer to a
procedure in a different langauge, I'd be grateful for a reply.

Again, I apologize if I'm just being dense, but...


Rich Wagner

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

* Re: ForTran-Ada + flamette + questi
  1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
@ 1986-06-22  3:00     ` Russ Holden
  1986-06-22  7:49     ` Enumerated "procedural" parameters Alastair Milne
  1986-07-10 22:26     ` ForTran-Ada + flamette + questi friesen
  2 siblings, 0 replies; 23+ messages in thread
From: Russ Holden @ 1986-06-22  3:00 UTC (permalink / raw)


I know this has been beaten to death (and put to sleep) but...

> >>  Rich, you are missing out on the beauty of procedure passing.
> >>  Simply put it gives you the ability to dynamically bind actions
 
> So does the enumeration-to-procedure mapping method I proposed.
> 
> To be more concrete, the following outlines a package spec which
> one could use:
> 
>     package Mapper is
> 
>           type No_Argument_Procedure_Pointer is (
>               proc_A_0, proc_B_0, ... );
> 
>           type One_Integer_Argument_Procedure_Pointer is (
>               proc_A_1_int, proc_B_1_int, ... );
>                    :
> 
>           procedure Call (
>               p : in No_Argument_Procedure_Pointer );
> 
>           procedure Call (
>               p : in One_Integer_Argument_Procedure_Pointer;
>               i : in Integer );
>                    :
>     end Mapper
> 
> The implementation of each "Call" procedure would simply be a case
> statement to the appropriate "real" procedure call.

There were a bunch of examples better than the ones I provided given
during the lengthy discussion about procedure parameters over the
past few weeks which point out the insufficiency of this (not to
mention its inherent ugliness and limits).  Also shown were mechanism
for making the checking of procedure parameters quite possible (for
example by requiring that procedures used in that manner be strongly 
typed).

> 
> If anyone could provide an example where a Procedure_Pointer could
> not be used wherever one would like to use a "real" pointer to a
> procedure in a different langauge, I'd be grateful for a reply.
> 
> Again, I apologize if I'm just being dense, but...
> 

OK, apology accepted.  


-- 
Russell Holden
Computer Corporation of America
Four Cambridge Center
Cambridge, MA 02142

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

* Re: Enumerated "procedural" parameters
  1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
  1986-06-22  3:00     ` Russ Holden
@ 1986-06-22  7:49     ` Alastair Milne
  1986-07-03  7:03       ` Dick Dunn
  1986-07-10 22:26     ` ForTran-Ada + flamette + questi friesen
  2 siblings, 1 reply; 23+ messages in thread
From: Alastair Milne @ 1986-06-22  7:49 UTC (permalink / raw)



    Using an enumeration-indexed case to choose the procedure to be called
    will work if all the procedures to be called are known and available at
    the time that case is compiled.  It will therefore work if all the
    enumeration-passing calls are in the same program unit as the case, or if
    they are exported by a package which will permit only "procedures" known
    to it (its own, or others from packages used in the specification) to be 
    passed in.

    It will not work in a library package exporting routines to be applied to 
    routines from units not known to the package.  Routines that come to mind 
    immediately are in the field of numeric analysis: curve fitting, best fits,
    adaptive quadrature, etc. .  In these cases what one needs is a routine 
    which, given some routine x to produce original function values, calls 
    that routine as it needs for input to its own algorithm.  Such packages
    would be essential parts of libraries for numeric analysis.  Their routines
    could be applied to any data-producing routine a user supplied,
    with algorithms 50 years old or produced yesterday.  But in Ada, the old 
    approach of simply passing that routine as another parameter is 
    not available.

    A good point has already been made on this board that in using Ada, one
    can find that the way one used to do something is no longer available,
    only to discover that it can be done in new and superior, more secure ways.
    I hope that will turn out to be so of this case.


    Alastair Milne

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

* Re: Enumerated "procedural" parameters
  1986-06-22  7:49     ` Enumerated "procedural" parameters Alastair Milne
@ 1986-07-03  7:03       ` Dick Dunn
  0 siblings, 0 replies; 23+ messages in thread
From: Dick Dunn @ 1986-07-03  7:03 UTC (permalink / raw)


I think it's unfortunate that anyone ever suggested the idea of enumerating
procedures which might be called and suppying an enumeration value instead
of a procedural parameter.  The question [I hope!] was never whether one
could construct an Ada program which would have the same effect as a
program in another language using procedural parameters...Turing
equivalence is a nice tool but it's not the point.

The fact that not all languages have procedural parameters gives some
weight to the Ada position.

The fact that C, Pascal, Modula, FORTRAN, Algol, and many other languages
do have procedural parameters gives weight to the position that the lack of
procedural parameters is a shortcoming of Ada.

The argument that procedural parameters can be simulated is really
irrelevant.  The issues have to do with convenience and safety, not simple
expressive power in a theoretical sense.  (Most languages are equivalent in
that theoretical sense.)  Hence the discussion would be much more useful if
it concentrated on Ada solutions which represent something like procedural
parameters with a notation comparably concise and convenient.  Adding an
enumerated type, constructing the (unenforced!) correspondence between
enumeration values and procedures, and replacing a single procedure
invocation with a case statement over an enumeration value (assuming that
the set of procedures of interest is actually a priori enumerable!) is not
at all the same in any way of interest to a practicing programmer.  A
better answer is necessary here.
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...Simpler is better.

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

* Re: ForTran-Ada + flamette + questi
  1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
  1986-06-22  3:00     ` Russ Holden
  1986-06-22  7:49     ` Enumerated "procedural" parameters Alastair Milne
@ 1986-07-10 22:26     ` friesen
  1986-07-11 15:38       ` ForTran-Ada ... (really function pointers) markb
  2 siblings, 1 reply; 23+ messages in thread
From: friesen @ 1986-07-10 22:26 UTC (permalink / raw)


In article <4700042@ada-uts> richw@ada-uts writes:
>
>>>  Simply put it gives you the ability to dynamically bind actions
>>>  without the invoker of the procedure having to know about the
>>>  procedure being called.
>
>So does the enumeration-to-procedure mapping method I proposed.
>
>>>                         ...  The use of enumerated types does no
>>>  good and there are no real good solutions that I know of in ADA
>
>I'm sorry, but I simply fail to see how your examples provide
>conclusive arguments that this method will not work in general.
>GRANTED, the mapping method is less convenient for the programmer,
>but my point was that it is nevertheless possible in Ada at a
>reasonable expense (which I think is justifiable given that omitting
>procedure pointers from Ada prevented Ada from becoming even more
>complex).
>
        I fail to see how an enumeration can solve the general
problem(even given your example). Given that at the time you write the
mapper package you do *not* know what procedures will be called by it,
and that *most* of the procedures to be used do not even exist yet,
*how* can you create an enumeration type that covers the set? The
whole point of function pointers as arguments is that it allows the
writing of *generic* procedures which can be "customized" by the
individual user by providing a pointer to a user supplied routine,
this allows the general routine to be used on data structures or
views that were not anticipated when the original routine was
written. If you can explain how to access non-existant functions,
whose names you do not even know, using an enumeration mapper, then I
will I will admit that this is equivalent to function pointers.
--

                                Sarima (Stanley Friesen)

UUCP: {ttidca|ihnp4|sdcrdcf|quad1|nrcvax|bellcore|logico}!psivax!friesen
ARPA: ??

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

* Re: ForTran-Ada ... (really function pointers)
  1986-07-10 22:26     ` ForTran-Ada + flamette + questi friesen
@ 1986-07-11 15:38       ` markb
  0 siblings, 0 replies; 23+ messages in thread
From: markb @ 1986-07-11 15:38 UTC (permalink / raw)


For 95% of the cases (e.g., Intgrators, numerical analysis, graphics etc.)
Generics provide a reasonable replacement for function pointers.
The other 5% of the time (e.g., EMACS) the emuneration mapping seems
to provide a moderatly reasonable replacement.  I have still not seen an
example that is not covered by one of these two alternitives.

Mark Biggar
{allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb

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

* Re: ForTran-Ada + flamette + questi
  1986-05-30 12:46 ` Russ Holden
  1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
@ 1986-07-14 17:01   ` richw
  1986-07-18 21:59     ` vilot
  1986-07-22 12:59   ` stt
  2 siblings, 1 reply; 23+ messages in thread
From: richw @ 1986-07-14 17:01 UTC (permalink / raw)



Sarima (Stanley Friesen) writes:

>>          I fail to see how an enumeration can solve the general
>>  problem (even given your example).  Given that at the time you
>>  write the mapper package you do *not* know what procedures will
>>  be called by it, and that *most* of the procedures to be used do
>>  not even exist yet, *how* can you create an enumeration type
>>  that covers the set?

Your point is valid; I did not explicitly state that modification of
the mapper package is necessary when newly written procedures are to
be passed (I didn't realize this wasn't obvious).  So, in terms of
program maintainance, yes, the mapping method is less convenient; if
you remember, I admitted from the onset that it WAS less convenient.
In any case, thanks for pointing out this ambiguity.

(Note, however, that the pain of having to modify the mapper package
 has nothing to do with WHAT you can do using the method; this mapping
 method STILL provides the same functionality as procedure passing.)

This raises an interesting question: can the mapper package be written
so that when new procedures are to be added, only the body of the
mapper package needs to be recompiled?  This is important when consider-
ing program maintainance because a change to the mapper package's spec
will force recompilation of all users of the mapper (something one would
like to avoid).  The last part of this note outlines a revised spec and
body which avoids having to modify the spec when adding procedures.

>>  The whole point of function pointers as arguments is that it
>>  allows the writing of *generic* procedures which can be
>>  "customized" by the individual user by providing a pointer to a
>>  user supplied routine, this allows the general routine to be
>>  used on data structures or views that were not anticipated when
>>  the original routine was written.

Ah, I'm GLAD you mentioned this.  The use of Ada's generics for such
situations is MUCH more advantageous than passing pointers.  If you
think about it, you can write a much more general "sort" procedure
using generics as opposed to procedure passing because generics lets
you not only vary the procedure used in comparing elements while
sorting -- it also lets you parameterize the TYPE of the elements in
the array you're sorting (assuming you're sorting arrays); can't do
that with procedure passing...


The following is that revised mapper package sketch I promised earlier;
it illustrates how one would pass two types of subprograms: simple
procedures which take no arguments and functions on Strings which return
Integers.

The basic idea involves moving the enumeration type declaration into
the package body.  The 'POS of the enumeration values are passed
around instead of the values themselves.  To make up for the
inability of users to refer to enumeration values by name (since
they no longer appear in the spec), the 'IMAGEs of the enumeration
values are used to create procedure pointers instead.  The costs of
changing the spec in these ways are: (1) More overhead due to the
use of 'VALUE in the body ('POS is not costly -- basically just a
type conversion) and (2) A misspelled procedure name is caught at
runtime (via the UNKNOWN_SUBPROGRAM exception) rather than link
time.

------------------------------------------------------------------------

package Mapper is

    type Procedure_with_0_arguments is private;
    type Function_with_1_in_String_return_Integer is private;

    UNKNOWN_SUBPROGRAM : exception;

    function Create (procedure_name : in String)
        return Procedure_with_0_arguments;
        -- Raises : UNKNOWN_SUBPROGRAM
    function Create (function_name : in String)
        return Function_with_1_in_String_return_Integer;
        -- Raises : UNKNOWN_SUBPROGRAM

    procedure Call (
        p : in Procedure_with_0_arguments);
    function  Call (
        f : in Function_with_1_in_String_return_Integer;
        s : in String)
            return Integer;

    procedure Call (
        procedure_name : in String);
        --
        -- Raises : UNKNOWN_SUBPROGRAM
        --
        -- This is functionally equivalent to:
        --           Call (Create (procedure_name));
        --
    function Call (
        function_name : in String;
        s : in String)
            return Integer;
        --
        -- Raises : UNKNOWN_SUBPROGRAM
        --
        -- This is functionally equivalent to:
        --           Call (Create (function_name), s);

private

    type Procedure_with_0_arguments is new Integer;
    type Function_with_1_in_String_return_Integer is new Integer;

end;

----------------------------------------------------------------------

with proc1;
with proc2;
with func1;
with func2;
     :

package body Mapper is

    type Enums_for_Procedure_with_0_arguments is (
        proc1_enum, proc2_enum, ...);
    type Enums_for_Function_with_1_in_String_return_Integer is (
        func1_enum, func2_enum, ...);
    --
    -- The above will need to be added to when new subprograms are
    -- to be passed.

    function Create (procedure_name : in String)
        return Procedure_with_0_arguments
    is begin
        return Enums_for_Procedure_with_0_arguments'POS (
               Enums_for_Procedure_with_0_arguments'VALUE (
                   procedure_name & "_enum"));
    exception
        when CONSTRAINT_ERROR =>
             raise UNKNOWN_SUBPROGRAM;
    end;

    function Create (function_name : in String)
        return Function_with_1_in_String_return_Integer
    is begin
        return Enums_for_Function_with_1_in_String_return_Integer'POS (
               Enums_for_Function_with_1_in_String_return_Integer'VALUE (
                   function_name & "_enum"));
    exception
        when CONSTRAINT_ERROR =>
             raise UNKNOWN_SUBPROGRAM;
    end;

    -- The following two subprograms will need to be added to when
    -- new subprograms are to be passed.
    --
    procedure Call (p : in Procedure_with_0_arguments)
    is begin
        case Enums_for_Procedure_with_0_arguments'VAL (p) is
            when proc1_enum => proc1;
            when proc2_enum => proc2;
                     :
        end case;
    end;

    function  Call (
        f : in Function_with_1_in_String_return_Integer;
        s : in String)
            return Integer
    is begin
        case Enums_for_Function_with_1_in_String_return_Integer'VAL (f) is
            when func1_enum => return func1 (s);
            when func2_enum => return func2 (s);
                     :
        end case;
    end;

    procedure Call (
        procedure_name : in String)
    is begin
        Call (Create (procedure_name));
    end;

    function Call (
        function_name : in String;
        s : in String)
            return Integer
    is begin
        return Call (Create (function_name), s);
    end;

end;

------------------------------------------------------------------------

Note the "_enum" suffixes for the enumeration literals; I included them
because I'm not sure offhand if there'd be any problem with overloading
the enumeration literals and the subprogram names they represent.

If not, then removing the "_enum" suffix (and removing the call to "&"
in the Create functions) would be a good thing; in any case, you get the
idea...

-- Rich Wagner

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

* Re: ForTran-Ada + flamette + questi
  1986-07-14 17:01   ` ForTran-Ada + flamette + questi richw
@ 1986-07-18 21:59     ` vilot
  0 siblings, 0 replies; 23+ messages in thread
From: vilot @ 1986-07-18 21:59 UTC (permalink / raw)


In article <4700062@ada-uts> richw@ada-uts writes:
>
>Sarima (Stanley Friesen) writes:
>
>>>          I fail to see how an enumeration can solve the general
>>>  problem (even given your example).  Given that at the time you
>>>  write the mapper package you do *not* know what procedures will
>>>  be called by it, and that *most* of the procedures to be used do
>>>  not even exist yet, *how* can you create an enumeration type
>>>  that covers the set?
>
>Your point is valid; I did not explicitly state that modification of
>the mapper package is necessary when newly written procedures are to
>be passed (I didn't realize this wasn't obvious).  So, in terms of
>program maintainance, yes, the mapping method is less convenient; if
>you remember, I admitted from the onset that it WAS less convenient.
>In any case, thanks for pointing out this ambiguity.
>
>(Note, however, that the pain of having to modify the mapper package
> has nothing to do with WHAT you can do using the method; this mapping
> method STILL provides the same functionality as procedure passing.)
>

I noticed that passing objects of type task was rejected very early in
this discussion.  Why?  (Please don't plead  run-time  "performance".)

It seems to provide  a reasonable approximation of  C's semantics  for
passing  function  pointers.   Ignoring  the   aesthetic arguments and
assuming someone  Really  Needs to do  this, are there any significant
reasons why it cannot be used to solve the problem?

(P.S. A simple bit of code passed the Verdix compiler, at least.)

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

* Re: ForTran-Ada + flamette + questi
  1986-05-30 12:46 ` Russ Holden
  1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
  1986-07-14 17:01   ` ForTran-Ada + flamette + questi richw
@ 1986-07-22 12:59   ` stt
  1986-08-07 13:26     ` Christopher Reedy
  2 siblings, 1 reply; 23+ messages in thread
From: stt @ 1986-07-22 12:59 UTC (permalink / raw)



Unfortunately, passing a task doesn't do the trick
because the task type (which must be specified) implies
the code for the task.  Of course tasks are great for
holding onto a bit of state, if that is your primary goal.

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

* Re: ForTran-Ada + flamette + questi
  1986-07-22 12:59   ` stt
@ 1986-08-07 13:26     ` Christopher Reedy
  0 siblings, 0 replies; 23+ messages in thread
From: Christopher Reedy @ 1986-08-07 13:26 UTC (permalink / raw)


Since I didn't see any responses to this:
In article <4700073@ada-uts> stt@ada-uts writes:
>
>Unfortunately, passing a task doesn't do the trick
>because the task type (which must be specified) implies
>the code for the task.  Of course tasks are great for
>holding onto a bit of state, if that is your primary goal.

There was a nice talk given at the 1985 Ada Europe conference in Paris
on this issue.  The thrust of the talk was that one needs an additional
task to act as an intermediary between the invoking and the invoked
tasks.  The intermediary task makes no entry calls, simply receiving
calls from both of the other tasks.  Thus, the invoking task need not
know the type of the invoked task.  (If anyone would like to see a
simple example, I have one.  However, it takes about three pages of
listing.)

In most cases this seems like a lot of overhead to go through to make a
variable procedure call.  However, the classical asynchronous buffer is
an example of this sort of approach.  In fact, if one was to combine the
intermediary task with an asynchronous buffer or some similar mechanism,
this approach might make a great deal of sense.

Chris Reedy
Computer Corporation of America
--Standard disclaimer: All opinions are my own.--

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

end of thread, other threads:[~1986-08-07 13:26 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1986-05-28 15:54 ForTran-Ada + flamette + question richw
1986-05-30 12:46 ` Russ Holden
1986-06-20 15:36   ` ForTran-Ada + flamette + questi richw
1986-06-22  3:00     ` Russ Holden
1986-06-22  7:49     ` Enumerated "procedural" parameters Alastair Milne
1986-07-03  7:03       ` Dick Dunn
1986-07-10 22:26     ` ForTran-Ada + flamette + questi friesen
1986-07-11 15:38       ` ForTran-Ada ... (really function pointers) markb
1986-07-14 17:01   ` ForTran-Ada + flamette + questi richw
1986-07-18 21:59     ` vilot
1986-07-22 12:59   ` stt
1986-08-07 13:26     ` Christopher Reedy
  -- strict thread matches above, loose matches on Subject: below --
1986-05-28 16:56 ForTran-Ada + flamette + question richw
1986-05-30 16:28 ` Vincent P. Broman
1986-06-02 16:28   ` Jonathan P. Biggar
1986-06-03  5:11     ` Barry Margolin
1986-06-03 12:39     ` Russ Holden
1986-06-04 23:39   ` Bryce Bardin
     [not found] <175155@QZCOM>
1986-05-22  1:00 ` Jan_Michael_Rynning
1986-05-21  6:06 larry
1986-05-21 15:41 ` Mark Biggar
1986-05-21 16:40 ` broman
1986-05-28 19:30 ` David Lamb

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