[net.lang.ada] ForTran-Ada + flamette + question

larry@JPL-VLSI.ARPA (05/21/86)

>  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

markb@sdcrdcf.UUCP (Mark Biggar) (05/21/86)

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

broman@noscvax.UUCP (05/21/86)

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

Jan_Michael_Rynning@QZCOM.MAILNET (05/22/86)

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.

richw@ada-uts (05/28/86)

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

richw@ada-uts (05/28/86)

> 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

dalamb@qucis.UUCP (David Lamb) (05/28/86)

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).

holden@cca.UUCP (Russ Holden) (05/30/86)

> 
> 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

broman@noscvax.UUCP (Vincent P. Broman) (05/30/86)

<>

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

jonab@sdcjove.UUCP (Jonathan P. Biggar) (06/02/86)

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)

barmar@mit-eddie.MIT.EDU (Barry Margolin) (06/03/86)

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

holden@cca.UUCP (Russ Holden) (06/03/86)

> 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

BBardin@USC-ISIF.ARPA (Bryce Bardin) (06/05/86)

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
-------