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