sommar@enea.se (Erland Sommarskog) (01/22/89)
Some while ago I asked the following: >But to throw some new wood on the fire, consider the following: Assume >you have routine you want to call but whose name you don't know until >run-time, thus you have the name in a string. Now in which langauges >can you easily do this? Interpreting langauges like Lisp and Basic, >support this I guess. But compiled langauges? Since then several people have answered in various waays. First, some posters have corrected me and pointed out that Lisp could be compiled too. Of course, there is no particular problem with implementing this in a compiled langauge; the problem lies in that the compiler can't perform the validation we often expect it to. Whether parameter profiles will match or not it can't tell. (Well, if we are using some 3rd class language we are not expecting this validation anyway.) Just finding the procedure to call it's simply a matter of having suffcient symbol information around. Someone said that this was just like a CASE statement in language in Ada or Pascal. Most emphatically: IT'S NOT! I'll present you later with a problem which isn't solveable with a simple CASE. Someone told us about $entry in PRIMOS(?). And VMS has LIB$Find_image_symbol for finding the address to a name, and then LIB$CallG for calling it. Unix surely have something similar. Yes, this seems like the way to go. Rely on what the OS gives you. Not very portable though. Peter da Silva (peter@ficc.uu.net) said: >I do this all the time in 'C', for one reason or another. >... >} funtab[] = { > "fname1", func1, > "fname2", func2, >... This is of course no better no solution than the CASE proposal. Maybe a litlte more convenient, but still have one serious problem: the names of the routines to call must be known at coding time. The problem I talked of: A general reusable menu handler. When the end-user starts the program he gets the main menu. He types a code which the menu handler looks up in the database. The code may refer to another menu which in this case is displayed. It may also refer to a specific function. In this case the menu handler calls the routine whose *name* it found in the database. The menu handler here is a reusable module which you link into your system, probably as the main program. This is where the CASE solution is totally unsatisfactory. For every new function we add, we have to modify the menu handler. Not talking of the case of moving to another application with new names and function codes. But Peter's function tables? Could one not require that every function loads a table entry at startup with itself? The global access cannot be a problem. Unfortunately, there is a little obstacle. To do the loading the module has to be activated. But by whom? The menu handler does at this stage not know about it. So you have to have some other code that knows about all functions in the system, and this is exactly what we want to avoid. (The self-loading approach could maybe work in a language with parallell processes, but I fail to find something workable for Ada. And if there is something it is a big overkill anyway.) So in what langauge can you implement the calling-part of this menu handler without calling some OS function? (It will be interesting to see what ideas that turn up this time.) -- Erland Sommarskog ENEA Data, Stockholm This signature is not to be quoted. sommar@enea.se
db@lfcs.ed.ac.uk (Dave Berry) (01/24/89)
In article <4261@enea.se> sommar@enea.se (Erland Sommarskog) writes: > But Peter's function tables? Could one not require that every >function loads a table entry at startup with itself? The global access >cannot be a problem. Unfortunately, there is a little obstacle. >To do the loading the module has to be activated. But by whom? The >menu handler does at this stage not know about it. So you have to >have some other code that knows about all functions in the system, >and this is exactly what we want to avoid. I'm not sure I understand this example. Couldn't one use a generic menu handler that takes a list of names and a symbol table as a parameter? I don't see why you need to avoid a piece of code that knows about all the functions in scope in your system, provided that that code doesn't constrain the men handler to dealing with a specific system. Dave Berry, Laboratory for Foundations of Computer Science, Edinburgh. db%lfcs.ed.ac.uk@nss.cs.ucl.ac.uk <Atlantic Ocean>!mcvax!ukc!lfcs!db
peter@ficc.uu.net (Peter da Silva) (01/24/89)
In article <4261@enea.se>, sommar@enea.se (Erland Sommarskog) writes: > But Peter's function tables? Could one not require that every > function loads a table entry at startup with itself? The global access > cannot be a problem. Unfortunately, there is a little obstacle. > To do the loading the module has to be activated. But by whom? The > menu handler does at this stage not know about it. So you have to > have some other code that knows about all functions in the system, > and this is exactly what we want to avoid. Well, there are a number of objections to this argument. First of all, not all functions are suitable for use in a menu... even in a language like Forth. Lisp, where each routine effectively validates all its arguments at run time might be able to get away with this, but the overhead seems a little high. The programmer knows which functions do make sense, and can stick them in the table. Secondly, some languages (Modula, for example) do have an initialisation section for each module. Stick them here. Finally, have you never heard of a preprocessor? Put this in your code: function(args) /* %id "name" */ ... Then run the following script from your makefile: sed -n '/%id/s/\(.*\)(.*%id \(".*"\).*/ \2, \1,/' *.c > functab.i And finally: functab.c: struct { char *name; int (*func)(); } functab { #include "functab.i" }; ... > So in what langauge can you implement the calling-part of this menu > handler without calling some OS function? (It will be interesting to > see what ideas that turn up this time.) If you really want to be sick, you can do this: call.h: struct fentry { char tag[4], *name; int (*func)(); }; #include "call.h" struct fentry foobar_entry = { "%id", "foobar", foobar }; And then do a linear search through memory for the unique tag string at startup time. Gross, wot? I got the inspiration for this from some guy's 'C' garbage collection code. -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. `-_-' Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net. 'U` Opinions may not represent the policies of FICC or the Xenix Support group.
mcdonald@uxe.cso.uiuc.edu (01/27/89)
>Some while ago I asked the following: >But to throw some new wood on the fire, consider the following: Assume >you have routine you want to call but whose name you don't know until >run-time, thus you have the name in a string. Now in which langauges >can you easily do this? Interpreting langauges like Lisp and Basic, >support this I guess. But compiled langauges? I think that you are asking the wrong question, or maybe only a subset of the full question. There are lots of languages (most?) where you could find a way of getting to any routine known at original compile-time. The real problem comes in getting at routines COMPILED at run time. This often becomes an operating system question: it appears that there are operating systems where it is impossible without logging in from the operator's console. Doug McDonald
jefu@pawl.rpi.edu (Jeffrey Putnam) (01/29/89)
In article <51300013@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes: >>Some while ago I asked the following: >>But to throw some new wood on the fire, consider the following: Assume >>you have routine you want to call but whose name you don't know until >>run-time, thus you have the name in a string. Now in which langauges >>can you easily do this? Interpreting langauges like Lisp and Basic, >>support this I guess. But compiled langauges? >I think that you are asking the wrong question, or maybe only a subset >of the full question. There are lots of languages (most?) where you >could find a way of getting to any routine known at original >compile-time. The real problem comes in getting at routines COMPILED >at run time. This often becomes an operating system question: it appears >that there are operating systems where it is impossible without >logging in from the operator's console. I have been following this discussion for a while and just realized this morning that it is possible that everyone has been asking the wrong question. (Parenthetically, i worked out a scheme whereby a C program compiled with debugging stuff on could read its symbol table and then jump to the address of the appropriate subroutine. Cute.) The question is, "why do you want to do this?" Im sure that there are valid reasons for wanting to do something like this, (i can think of many) but in most cases, what is wanted is not to be able to jump to just any subroutine, but only to some specific subset of the subroutines. In that case, there is no reason not to use a compiled table of "name -> address" as has been previously suggested. (But, as mentioned above, this compiled table might be produced by the C compiler (ick!).) jeff putnam -- "Sometimes one must attempt the impossible if only to jefu@pawl.rpi.edu -- show it is merely inadvisable."
sommar@enea.se (Erland Sommarskog) (01/30/89)
It's possible I have missed some responses to my previous article, news flow seems to have been incomplete last week, so there is a risk someone has said what I wanted to hear. Anyway, this article tells how the menu handler I talked of actually was implemented. Some replay for newcomers: In the discussion about Bondage & Discipline langauges I said that a lanaguge like C was a B&D language if I want to call a routine by its name which I have in a string. As an example I gave a menu handler that should be reusable, and with knowledge of the routines in the application within its code, but in a user-loaded database. But before I give the final clues and reveal the answer some comments to other people comments. Beside the articles, I got some mail too. Obviously it would be trivial to implement the menu handler (at least the calling part of it) in Lisp, Scheme and PS-Algol. Then there was a discussion of C. And, yes, in every practical case, we can implement the handler in C. Either we could ship the menu handler with a program that reads the database and from that generates the code that loads a function table. This generated module would then be linked with the system and called at startup. (Or be the startup program itself.) Another solution if you are on Unix if to use nlist(3) that someone pointed out to me. This may not be portable, though. So we can use C, yes, but with a lot of work and inconvenince. Clearly a case of B&D it seems to me. In Modula which has initiation parts in the module we could require that each menu-selection routine loads itself in the initiation part. However, we run the risk theat the application programmer is messing things up. (Typically one such routine is in a module of its, since it more or less an independent program.) It works, but it's still B&D. One language that hasn't been mentioned is MUMPS. In MUMPS you have XECUTE, which simple executes its string argument. (This is an interpreted langauge, so it's easy.) The string could of course be a procedure call as anything else. I thought this could be common in some BASICs too, that's why I originally mentioned BASIC. As a whole such constructs are easy to implement in interpreted langauges. Not so easy in compiled ones. (DEC editor langauge VAXTPU is an example, though.) But the manu handler I talked of is more than just a theoretical idea. It exists. Not written by me, but by the people I currently work with. What language did they use? Clue 1: It hasn't been mentioned in the call-by-string discussion so far, possibly in the previous B&D language, as an example of a B&D langauge. Clue 2: It doesn't have a newsgroup of its own on the net. Some obscure langauge that no one has heard of? Not really. In fact, Clue 3: There is an ANSI standard for it. Latest revision in 1985. Clue 4: The previous ANSI standard is from 1974. Clue 5: (Now it's getting easy.) It's probably the world's most commonly used programming langauge. Answer: COBOL. It's very simple. The construct is: CALL Nisse USING Parameter1, Parameter2.... where Nisse is a string variable. (PIC X(32) or so.) If Nisse is the name of a routine you want to call, you use quotes: CALL "Nisse" USING Parameter1, Parameter2... Compare this with loading function tables and I don't know what in C! Then on the other hand, there are of course things that are simpler to carry out in C. So that's the point: what's is B&D depends on what you want to do. Or in clear text: This talk of B&D is just rubbish. It's interesting to the see in this company of bright people, no one mentions Cobol. Reveales that the net community is maybe not perfectly representable for the programmer community at large. But don't feel ashamed. I didn't know this capability in Cobol a year ago. Addendum on the menu handler: Since I have mentioned it, some more details could be of interest to you. First, it is not written in Cobol, only the routine that calls the application routine is. The rest is in VAX-Pascal. And since our application also is in VAX-Pascal, every application routine needs a little link program in Cobol, since there is a restriction with the CALL identifier construct, saying that the called routine must be another Cobol routine. Actually, we are about to abandon the Cobol solution. The reason is that with Cobol we must link all routines into one image and it gets large, 9000+ blocks. (A block = 512 bytes.) So we're aiming at shareable images instead, which would mean LIB$Find_image_symbol. What we hope to do, but don't know the performance penalty for it yet, is to have every application routine as a shareable image (there are around 200 of them currently), which would mean a fix in such a program can be delivered instantly. And not only the menu handler's code will be application independent, but also the its executeable will be. Talk about modular software! (And before someone ask: yes we will put common routines in shareable images a la run-time libraries as well.) Ahum, if you follow up on this addendum, it's probably not a langauge issue, so look for another newsgroup. -- Erland Sommarskog ENEA Data, Stockholm This signature is not to be quoted. sommar@enea.se
amanda@iesd.uucp (Per Abrahamsen) (01/31/89)
In article <4279@enea.se> sommar@enea.se (Erland Sommarskog) writes: > Then on the other hand, there are of course things that are simpler >to carry out in C. So that's the point: what's is B&D depends on what >you want to do. Or in clear text: This talk of B&D is just rubbish. Who said a language was "B&D" when it made something difficult to do? The claim was that a language was B&D when the designer intentionally made something difficult, in order to protect the programmer from himself. C and Modula 2 don't have a "call string" because it would be difficult and inefficient to implement in these languages, not because Richie & Wirth thought it was wrong. -- Per Abrahamsen, amanda@iesd.dk, {...}!mcvax!diku!iesd!amanda
djones@megatest.UUCP (Dave Jones) (01/31/89)
From article <403@rpi.edu>, by jefu@pawl.rpi.edu (Jeffrey Putnam): ... > I have been following this discussion for a while and just realized this > morning that it is possible that everyone has been asking the wrong question. > (Parenthetically, i worked out a scheme whereby a C program compiled with > debugging stuff on could read its symbol table and then jump to the > address of the appropriate subroutine. Cute.) > Under BSD4.2 and Sun3, it is not even necessary to compile with debugging stuff. Just don't strip out the symbol-table. > The question is, "why do you want to do this?" ... The reason might be that the procedure you want to jump to was compiled after the main program was compiled, and was not, and could not be, known to the main program at the time of its compilation. I'll give you a real world example. Well, it's real world if you include manufacturing and testing computer parts as "real world". Let's suppose you have engineers all over the world who come up with designs for ASIC parts. Each of these part-specifications generates a procedure which tests the part. A program monitors loading chips or wafers by robot, interacting with the operator, etc., and it keeps timing calibration and other data concerning the tester itself. The program has to be able to call any of these part-specific procedures which had not even been written when the main program was written. But putting each part-specific procedure in its own process would be prohibitively expensive without some mechanism for shared data: It would take too long to initialize it with the calibration data, etc., and it would require too much memory, even with today's multimegabyte rams. So the program needs to read the part-specific procedure into memory, and then branch to it.
djones@megatest.UUCP (Dave Jones) (01/31/89)
From article <4279@enea.se>, by sommar@enea.se (Erland Sommarskog): ... > Some replay for newcomers: In the discussion about Bondage & > Discipline langauges I said that a lanaguge like C was a B&D > language if I want to call a routine by its name which I have > in a string. As I understand it, the originators of the term, "B&D language" use it to refer to languages which prevent or make difficult certain kinds of programming, not by simple omission, but because the language designers deemed them Bad Things, and sought to prevent them by decree. C does not attempt to prevent you from writing a call-by-string routine. It just does not contain call-by-string as a feature, presumably because the Founding Fathers did not need it to write Unix. I have written call-by-string in C for BSD4.2 and Sun3, and it was not at all difficult. The only problem was deciphering the executable (dot-o) format. The C part was easy. Machine-independence is down the tubes, of course. By making it part of the language, you could move the porting problem from the application programmer to the C-library programmer, which might be a win, if enough people use the feature. But as it is, it's not B&D.
oster@dewey.soe.berkeley.edu (David Phillip Oster) (02/01/89)
Under the macintosh operatiing system, call by string is simply:
typedef long (*LFuncPtr)(); /* LFuncPtr is a pointer to a func
returning a long */
LFuncPtr *byString;
if(NULL != (byString = (LFuncPtr *)
GetNamedResource('XCMD',"\pYour Name Here"))){
HLock((Handle) byString);
(**byString)(arg1, arg2, arg3); /* your args here */
HUnlock((Handle byString);
}
explanation:
On the mac, every program has a built-in archive of data called "the
resource fork". The system call GetResource() fetches data by 4-char type
and integer id number. The system call GetNamedResource() fetches data by
f-char type and string name. The "\p" generates a length byte, which is
the kind of string GetNamedResource takes.
It doesn't return a ptr to the data, but a ptr to ptr. The extra level of
indirection lets the system move the data, if it needs to change its size,
so long as I always double indirect when I access through the ptr to ptr.
HLock() tells the system not to move this piece of data for a while.
(Can't have the code moving out from under the program counter while it is
executing!
You could repackage all of the above (except the HUnlock()) as a function
called "CallByString", that takes one argument, a string. It would lock
anmd return a pointer to the code object, if it found it. Otherwise, it
would return a pointer to an error routine.
Then you could say:
(*CallByString(stringVariable))(arg1, arg2, arg3)
You can't get much cleaner than that. C hardly seems to be a B&D language
here: as I have proved by demonstrating, with the right library support,
call by string isn't difficult at all in C.
No, if you want B&D, try to call C printf from Pascal. Try to write printf
in pascal.
frode@m2cs.uu.no (Frode Odegard) (02/01/89)
In article <4279@enea.se>, sommar@enea.se (Erland Sommarskog) writes: > In Modula which has initiation parts in the module we could require > that each menu-selection routine loads itself in the initiation part. > However, we run the risk theat the application programmer is messing > things up. (Typically one such routine is in a module of its, since > it more or less an independent program.) It works, but it's still B&D. > We're doing an environment for large Modula projects which includes lots of Interlisp-D/Symbolics features. It is quite easy to write Modula programs which write Modula programs and send them off to the interpreter or the incremental compilation system. The interpreter is yet another library module... [and this is not a toy, we're going to hit the embedded systems market HARD in a few months..incremental compilation reduces turn- around time a LOT]. - Frode -- | Frode L. Odegard |"The world is coming to an end! Repent and| | Modula-2 CASE Systems |rm /bin/cc" | | NORWAY (EUROPE) | | | Email: frode@m2cs.uu.no | |
nick@aimed.UUCP (Nick Pemberton) (02/01/89)
Well, being the PICK hack I am, I couldn't help enjoying watching people struggle with this one for a while. PICK's warped version of BASIC supports this feature. If a variable contains a string representing the name of a routine, one can do a call of the form: CALL @variable(arg1, [arg2, ...]) there is no limit on the number of arguments; the routine can be any cataloged routine (cataloged just means compiled and in a 'library'). We use it all the time for a generic window driver: It is a data driven application that has field descritors within it that are capable of calling any other BASIC routine. Very usefull. Indispensable, in fact. And yes, its possible because PICK BASIC is at least partially interpretted. Nick. -- Nick Pemberton UUCP: !{utzoo,utai}!lsuc!aimed!nick AIM, Inc Bus: (416) 429-4913 Home: (416) 690-0647
nevin1@ihlpb.ATT.COM (Liber) (02/03/89)
In article <4279@enea.se> sommar@enea.se (Erland Sommarskog) writes: >In the discussion about Bondage & >Discipline langauges I said that a lanaguge like C was a B&D >language if I want to call a routine by its name which I have >in a string. To be technically correct, what you should have said is that you want to call a routine by its name which you have in an array of char terminated by a null byte, and you think that C is a B&D language because it does not directly support any operations on arrays of char terminated by a null byte. "Strings" are NOT first class objects in C, nor should they be! No matter how you implement strings (special terminator, fixed length, keep size separately, etc.), there are always some applications where it is advantageous, and others where it is not. One of the benefits of C is that you can implement them any way you want; the language doesn't tie you down to one implementation. To call this B&D (besides not using the original poster's definition) is ludicrious. -- _ __ NEVIN ":-)" LIBER nevin1@ihlpb.ATT.COM (312) 979-4751 IH 4F-410 ' ) ) "I will not be pushed, filed, stamped, indexed, / / _ , __o ____ briefed, debriefed or numbered! My life is my own!" / (_</_\/ <__/ / <_ As far as I know, these are NOT the opinions of AT&T.
frode@m2cs.uu.no (Frode Odegard) (02/05/89)
In article <1260@iesd.uucp>, amanda@iesd.uucp (Per Abrahamsen) writes: > C and Modula 2 don't have a "call string" because it would be > difficult and inefficient to implement in these languages, not because > Richie & Wirth thought it was wrong. > > -- > Per Abrahamsen, amanda@iesd.dk, {...}!mcvax!diku!iesd!amanda Well, we're working on an Interlisp-D/Symbolics/Smalltalk -inspired Modula-2 environment on the Sun workstation. The system includes an interpreter and an incremental compilation system. In our environment programs can build data structures which are programs (or pieces of programs) and send them off to the intepreter. The system is based on using a special data structure for representing Modula-2 source code. This data structure can be manipulated using library modules available to toolmakers. The editor is pretty "intelligent" because it works on a higher level than text only. You can view module dependencies and stuff like that, and it is easy to write new tools which manipulate/write programs. We have built an o-o database server for managing all the data, and the user interface is NeWS-based. While not extending Modula-2 in itself, we're trying to provide a dynamic, LISP-inspired environment for Moduleans. The first release will target the embedded systems market, so the environment does support "Modula-2 -- the fast systems language". - Frode -- | Frode L. Odegard |"The world is coming to an end! Repent and| | Modula-2 CASE Systems |rm /bin/cc" | | NORWAY (EUROPE) | | | Email: frode@m2cs.uu.no | |
daveb@geaclib.UUCP (David Collier-Brown) (02/07/89)
On the off chance noone has mentioned it, the concept of calling a name expressed in an external format (ie, a string), is a basic mechanism in Multics, Unix's daddy. It wasn't a language feature, it was how you did linking. If you couldn't link by at least runtime, you got told about the problem and asked for a compiled function (or a different name) to satisfy the call request. This was not only useful, it also allowed you to do cute demonstrations of prototyping... -- David Collier-Brown. | yunexus!lethe!dave Interleaf Canada Inc. | 1550 Enterprise Rd. | He's so smart he's dumb. Mississauga, Ontario | --Joyce C-B
ch@maths.tcd.ie (Charles Bryant) (02/09/89)
In article <1316@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >From article <403@rpi.edu>, by jefu@pawl.rpi.edu (Jeffrey Putnam): >... > >The reason might be that the procedure you want to jump to was >compiled after the main program was compiled, and was not, and could >not be, known to the main program at the time of its compilation. >... Well here's another solution (which will work in many languages): write your C code with function definitions like this: char * /* or whatever */ /*CALLABLE*/ func_foo(a, b, c) { ... Then write a small program (awk/sed script or whatever you like) to read a file and take the first word of all lines following /*CALLABLE*/ and produce: struct calltable { void (*func)(); /* whatever type you want */ char *name; } my_call_table = { func_foo, "func_foo", . . . }; Now write a function which takes a string, looks it up in the table and calls it. By declaring the table 'extern', the program can be compiled, and the table can be generated and linked later. The parts of the program you don't need to be able to call can even be linked if your linker can produce one linkable object from several. -- Charles Bryant. Working at Datacode Electronics Ltd.