chris@mimsy.UUCP (Chris Torek) (05/07/88)
>In article <11325@mimsy.UUCP> I mentioned >>(Of course, if you add unnamed aggregates, you should also add >>unnamed functions.) In article <282@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) asks: >... How would unnamed functions be implemented? How would they be used? The implementation is obvious (he said smugly). You could even do it in a PCC-style compiler: /* source */ void bar(int (*fp)()); /* bar takes one argument */ void foo() { bar( /* call bar with the pointer from...: */ /* (here comes the anonymous function def.) */ int (){ int i; i = 3; return (i); } ); } /* sample dumb compiler output */ _foo: .globl _foo sub $L1,sp # create local frame space jbr L2 # branch around the anonymous fn. L3: sub $L4,sp # create local frame space mov $3,-4(fp) # i=3 mov -4(fp),r0 # return (i) ret .set L4,4 # anonymous function (L3) needs # 4 bytes of stack L2: push $L3 # push address of anonymous fn. call _bar # bar(...) pop r0 # clean up ret # end of foo() .set L1,0 # function foo needs 0 bytes As for uses, anonymous functions are much like anonymous aggregates: you use them to pass to other functions, or to set local variables (in C, pointers to functions). void foo() { void (*fp)() = void () { code; } ... (*fp)(); } -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
root@mfci.UUCP (SuperUser) (05/10/88)
Expires: Followup-To: Distribution: Keywords: In article <11385@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >In article <282@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) asks: >>... How would unnamed functions be implemented? How would they be used? > >The implementation is obvious (he said smugly). You could even do it >in a PCC-style compiler: > > /* source */ > void bar(int (*fp)()); /* bar takes one argument */ > > void > foo() { > bar( /* call bar with the pointer from...: */ > /* (here comes the anonymous function def.) */ > int (){ int i; i = 3; return (i); } > ); > } Of course, this opens a whole can of worms about how to handle up-level references to automatics, etc. For example, what does the following do? int x = 123; main() { int x = 456; void (*fp)() = void () { printf("%d\n", x); }; (*fp)(); } You could make the reference to x illegal, but it wouldn't last. Some implementations would give you the external x, so you'd get 123, and others would give you the local x, so you'd get 456. The latter would be more generally powerful and useful, but then you'd have to have displays, etc. You'd also be put in the position of justifying why named nested functions aren't supported, and you'd end up having to support those as well... >As for uses, anonymous functions are much like anonymous aggregates: >you use them to pass to other functions, or to set local variables >(in C, pointers to functions). > > void > foo() { > void (*fp)() = void () { code; } > ... > (*fp)(); > } Don't you mean: void foo() { void (*fp)() = void () { code }; ... (*fp)(); }
chris@mimsy.UUCP (Chris Torek) (05/11/88)
In article <393@m3.mfci.UUCP> root@mfci.UUCP (SuperUser) writes: >Of course, this opens a whole can of worms about how to handle up-level >references to automatics, etc. Just make it illegal. If you want access to some `parent's' variables (in quotes because to a large extent, the scoping is illusory), you must pass them to the anonymous function: > int x = 123; > main() { > int x = 456; > void (*fp)() = void () { printf("%d\n", x); }; > (*fp)(); > } becomes int x = 123; main() { int x = 456; void (*fp)(int) = void (int x) { printf("%d\n", x); }; (*fp)(x); } >You could make the reference to x illegal, but it wouldn't last. >[stuff about displays deleted] I admit it `tastes odd', yet I am not sure it would not last. I would much rather not require static links or displays; I feel that these are often just excess baggage: that they are not worth their cost. In practise, when I need access to uplevel variables, I do it through what I call contexts. These are rather similar to the class pointers C++ passes to class functions, which are accessed via the keyword `this'. In C, there is no keyword: you have to do it yourself: struct hitcontext { char *str; int hits; }; static void hits_helper(void *context, struct tentry *te) { struct hitcontext *f = context; if (strstr(te->te_name, f->str) != NULL) f->hits++; } int hits(char *str, struct table *t) { struct hitcontext hc; hc.str = str; hc.hits = 0; table_iterate(t, hits_helper, (void *)&hc); return (hc.hits); } (This is a simplified version of some real code.) In this case, it would be nice to keep both the hitcontext structure declaration and the hits_helper function definition local to function hits. Not necessary---just as unnamed aggregates are not necessary---but convenient. Can you imagine C without unnamed char arrays? int main() { static char S1[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 }; static char S2[] = {'i', ' ', '=', ' ', '%', 'd', '\n', 0 }; int i; printf(S1); ... printf(S2, i); return (0); } Yuck! Admittedly, anonymous functions are less useful in C than anonymous strings. [me:] >> foo() { >> void (*fp)() = void () { code; } >Don't you mean: > foo() { > void (*fp)() = void () { code }; Yes. (Just a typographic error....) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
throopw@xyzzy.UUCP (Wayne A. Throop) (05/11/88)
> chris@mimsy.UUCP (Chris Torek) Once again, Chris writes the exact article I had in mind, only better than I might have done it. I have only one nit to pick. In telling "what good are they" of anonymous functions, Chris says: > As for uses, anonymous functions are much like anonymous aggregates: > you use them to pass to other functions, or to set local variables > (in C, pointers to functions). ... which is exactly correct, but he omits giving a convincing example, like to supply a signal handler routine that just sets an external bit, or a compare or swap routine for a qsort, or a hash routine for a table manipulation routine, or whatever. The point is, why name this little bit of code that is required to be a function because of the way the library is organized? When extremely short as in these examples, giving it a name is silly and wastefull. Example invocations: signal( SIGINT, void (int sig){ interrupted = 1; } ); qsort( (void *)tbl, n_elt, n_elt*sizeof(tbl_elt_t), int (void *a, void *b){ return( strcmp( (tbl_elt_t *)a->name, (tbl_elt_t *)b->name ) ); } ); /* crummy hash function, but good enough for whatever purpose: */ hfind( name, table, int (char *s){ return(*s); } ); -- He wonders if he too might have made a similar mistake. --- "Seen and Not Seen" by Talking Heads from "Remain in Light" -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw
peter@ficc.UUCP (Peter da Silva) (05/18/88)
Reposted because news wasn't getting off-site. My fault. In article <282@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) writes: > The { .. } syntax for aggregate declar- > ations seems natural enough to use for unnamed aggregates, but how would it > be done for functions? (lambda nil (... Just kidding. How about: a = (int ()(int i)) { for(i=0; i < 10; i++) if(foo(i)==MAGIC) break; return i; }(b); And again: int (*f)(int) = &(int ()(int i)) { ... }; a = (*f)(b); Yow! Auto functions! Back to BCPL. But I think it's neat. In article <2706@geac.UUCP>, daveb@geac.UUCP (David Collier-Brown) writes: > | In article <11325@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > qsort(base, nel, width, compar) > char *base; > int (*compar)(); > EXAMPLE > qsort(base, nel, width, { return zcomp($1,$2) }); qsort(base, nel, width, &(int ()(int a, b)){ return zcomp(a, b); } ); > Note the problem with parameters... I'm actually beginning to like this syntax. Is this a fatal character flaw? -- -- Peter da Silva, Ferranti International Controls Corporation. -- Phone: 713-274-5180. Remote UUCP: uunet!nuchat!sugar!peter.
peter@ficc.UUCP (Peter da Silva) (05/19/88)
In article <862@xyzzy.UUCP>, throopw@xyzzy.UUCP writes: > signal( SIGINT, void (int sig){ interrupted = 1; } ); > qsort( (void *)tbl, n_elt, n_elt*sizeof(tbl_elt_t), > int (void *a, void *b){ > return( strcmp( (tbl_elt_t *)a->name, > (tbl_elt_t *)b->name ) ); } ); > /* crummy hash function, but good enough for whatever purpose: */ > hfind( name, table, int (char *s){ return(*s); } ); I think that the syntax is a bit wedged here. What you're actually doing is akin to typecasting: (void (*)(int sig)){ interrupted = 1; } (int (*)(void *a, void *b)) { ... } (int (*)(char *s)){ return s; } A bit more verbose, but should require less patching of the language definition. -- -- Peter da Silva, Ferranti International Controls Corporation. -- Phone: 713-274-5180. Remote UUCP: uunet!nuchat!sugar!peter.
peter@ficc.UUCP (Peter da Silva) (05/19/88)
In article <862@xyzzy.UUCP>, throopw@xyzzy.UUCP writes: > signal( SIGINT, void (int sig){ interrupted = 1; } ); Of course if you went with this syntax instead of the typecast syntax, there's no good reason to disallow: signal ( SIGINT, void (sig) int sig; { interrupted = 1; } ); After all, pre-ANSI declarations are still allowed. I'd hate to have to write the compiler, though. -- -- Peter da Silva, Ferranti International Controls Corporation. -- Phone: 713-274-5180. Remote UUCP: uunet!nuchat!sugar!peter.
mcgrath@tully.Berkeley.EDU.berkeley.edu (Roland McGrath) (05/21/88)
) I'm actually beginning to like this syntax. Is this a fatal character flaw? Oh, probably. But I've got many fatal flaws, they tell me, and you and I seem to be alive. Ah, but is your character alive? Well, perhaps not, but then you're unflawed, so rejoice!
karl@haddock.ISC.COM (Karl Heuer) (05/24/88)
In article <799@.UUCP> peter@ficc.UUCP (Peter da Silva) writes: >In article <862@xyzzy.UUCP>, throopw@xyzzy.UUCP writes: >> signal( SIGINT, void (int sig){ interrupted = 1; } ); >Of course if you went with this syntax instead of the typecast syntax, there's >no good reason to disallow: > signal ( SIGINT, void (sig) int sig; { interrupted = 1; } ); >After all, pre-ANSI declarations are still allowed. But they are obsolescent. They exist only for backward compatibility, which is not an issue when you're adding something new like anonymous functions. I'm not sure how easy it is to parse, anyway; I think I'd be satisfied with my earlier proposal: signal(SIGINT, remote(void (int sig), { interrupted = 1; })); ctime(&remote(long, 0)); Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint