Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!rpi!uupsi!cmcl2!kramden.acf.nyu.edu!brnstnd From: brnstnd@kramden.acf.nyu.edu (Dan Bernstein) Newsgroups: comp.lang.misc Subject: Re: The powerlessness of Lisp Message-ID: <26146:Mar2804:56:5791@kramden.acf.nyu.edu> Date: 28 Mar 91 04:56:57 GMT References: <1991Mar21.123512.22876@daffy.cs.wisc.edu> <16060:Mar2515:41:5691@kramden.acf.nyu.edu> <1991Mar26.165516.13035@daffy.cs.wisc.edu> Organization: IR Lines: 436 In article <1991Mar26.165516.13035@daffy.cs.wisc.edu> quale@saavik.cs.wisc.edu (Douglas E. Quale) writes: > Byte copying is trivial in Common Lisp. So translate *(int *)&buf = n; into Lisp. Here char *buf; int n. > A typical > "portable" C program running on n different platforms is usually n different > programs selected by conditional compilation via #ifdef's. What a load of crap. My latest compressor, for example, has so far been reported to work on platforms from about fifty vendors. Four of the configuration options enable optimizations that depend on available libraries. One enables extra code to handle a common stdio bug in older systems. Four set defaults for user options. The rest select between machine-independent optimizations. There aren't any #ifdefs other than the configuration options. This is hardly atypical of C programs. > Emacs is written in elisp. What a(nother) load of crap. Next Doug will be claim that sh, csh, and ksh are written not in C, but in shell code! After all, the vast majority of code that people use while executing the shell is, indeed, in an interpreted language, even if under the scenes there's that dirty C code actually running and doing all the work. > The major advantage of lisp over C here is the fact that > lisp is much more easily extensible. Yep, and the major advantage of sh over C here is the fact that sh is much more easily extensible. Do I conclude that sh is written in sh? Yes or no? > you are quite outrageous So who's abusing the English language? :-) > and completely > ignored my request for the literature you claim to have read showing that > software development and testing is faster in C than in Common Lisp. I never made such a claim. I said that compile time and run time were slower in dynamically typed languages; later I amended that to ``compile time or run time.'' More precisely, the literature shows the run time in dynamically typed languages as much slower than in statically typed languages. Research (mostly recent) on optimization of dynamically typed languages shows that the run time can come close (i.e., better than half the speed), but only at a huge expense in compile time. I believe these comments correctly summarize the relevant literature, and if you stop perverting my statements but are still too lazy to do your own homework, I'll give you sample references. > As for compose, your response was repeatedly, [ Doug exhibits his creative writing skills ] > If you really had > the stuff, prove it. Enclosed is another copy of the first article, since you didn't respond to any of my offers via email. This qualifies you as a royal asshole, by the way. Also enclosed for completeness are references to your first two articles implying that my compose() didn't work, and, just in case, one of the intermediate articles that you lied about. The interested reader (I doubt there are any) will note that my compose() nests properly, while Doug has said repeatedly that it doesn't. As I recall, he also claims to have been reading comp.lang.misc for more than three months. > You bristle when asked for any evidence that what you're saying isn't just > hot air. Yes, I do, as the challenges come from a perverting pain in the butt. I don't believe I have left any of your ``questions'' unanswered; I do hope that you learn some civility before you have the nerve to show your userid again in this newsgroup. If you claim once more that my compose() doesn't nest properly, or that I have been reticent in providing evidence that it does, I will feel no compunction in thrashing you in public for the next twenty mistakes you make. Don't take this as a threat, though; I don't want you to tell the truth until you understand that it really is the truth. ---Dan Path: kramden.acf.nyu.edu!brnstnd From: brnstnd@kramden.acf.nyu.edu (Dan Bernstein) Message-ID: <19468:Dec2100:23:0790@kramden.acf.nyu.edu> Date: Fri Dec 21 00:23:07 GMT 1990 Newsgroups: comp.lang.misc Subject: Look, Ma, I can dynamically compose functions in C! X-Original-Subject: Re: Complexity of syntax References: <20@garth.UUCP> <27534.276e5bd3@kuhub.cc.ukans.edu> <1990Dec19.222059.6878@mathrt0.math.chalmers.se> Organization: IR In article <1990Dec19.222059.6878@mathrt0.math.chalmers.se> augustss@cs.chalmers.se (Lennart Augustsson) writes: > To see the difference just try to write a function > that does function composition. Okay. (What follows isn't tested but you'll get the idea.) We'll work with a function descriptor type: struct basicfun { int (*f)(); } ; struct twofun { struct fun *first; struct fun *second; } struct fun { int type; union { struct basicfun b; struct twofun t; } u; } ; #define BASICTYPE 1 #define TWOTYPE 2 To convert a C function pointer into one of these things, given storage space: struct fun *cftofun(c,f) int (*c)(); struct fun *f; { f->type = BASICTYPE; f->u.b.f = c; return f; } To call one of these things, given the argument: int callfun(f,x) struct fun *f; int x; { switch(f->type) { case BASICTYPE: return f->u.b.f(x); case TWOTYPE: return callfun(f->u.t.second, callfun(f->u.t.first,x)); } } Finally, to answer the question: struct fun *compose(second,first,f) struct fun *second; struct fun *first; struct fun *f; { f->type = TWOTYPE; f->u.t.first = first; f->u.t.second = second; return f; } Of course, a more complete implementation would manage struct fun storage, possibly with garbage collection. A different strategy is to store basic functions as just pointers, and composed functions as a pointer to a special function, followed by the first and second pointers; then pointers to these ``objects'' would be passed in as arguments. Back to Lennart: > I claim that this is impossible to do in a portable way. You were saying? ---Dan Path: kramden.acf.nyu.edu!brnstnd From: brnstnd@kramden.acf.nyu.edu (Dan Bernstein) Newsgroups: comp.lang.misc Subject: Re: On whether C has first-class composable functions Message-ID: <25199:Feb801:33:1191@kramden.acf.nyu.edu> Date: Fri Feb 8 01:33:11 GMT 1991 References: <1991Feb6.161639.18311@spool.cs.wisc.edu> <12547:Feb621:05:4491@kramden.acf.nyu.edu> <1991Feb7.150537.9257@spool.cs.wisc.edu> Organization: IR Lines: 99 In article <1991Feb7.150537.9257@spool.cs.wisc.edu> quale@picard.cs.wisc.edu (Douglas E. Quale) writes: > Unfortunately, this doesn't solve the problem. Your `functions' are not > functions. What happens when I pass a Bernstein `function' to twalk(3c)?? ``Unfortunately, your bignum package doesn't solve the problem. Your `bignums' are not numbers. What happens when I pass a DECWRL bignum to getcwd()??'' The mistake here is the second statement. Bignums are numbers; they just aren't the same as C's integers. Similarly, anything supporting certain operations is a function; it doesn't have to be the same as C's functions. Your ``problem'' of passing a non-C-function to twalk() has been quite thoroughly addressed in other postings. Just because twalk() only accepts C functions doesn't mean that other functions aren't functions, either in theory or in practice. This has all been discussed to death before in this newsgroup. If you're trying to contribute something, make an effort to see what's already been contributed. > The question was NEVER, "Can C _implement_ dynamically allocable functions?" I chose the subject line (I choose most subject lines in comp.lang.misc these days) and I was using ``L has X'' to mean ``X can be implemented in L'' where L is a language and X is a semantic feature. Apparently people can't stand this usage, although nobody's been able to come up with any other sensible definition of ``has'' in this context; so I've stopped using ``has'' in this way. Nevertheless, that's what it means in the subject line. This has also been discussed to death before in this newsgroup. If you're trying to contribute something, make an effort to see what's already been contributed. > I can implement a Turing machine simulator in practically any language, > but it's not very interesting or useful. (Not in Fortran.) The reason that a Turing machine simulator isn't useful is that once you get down from theory to practice, you care about issues like efficiency. However, usefulness is not the same thing as power. Would you say that the original Forth doesn't have I/O facilities just because its I/O facilities aren't very useful? No. > Does C _have_ dynamically allocable functions? > No. What's your definition of ``has'' for a semantic feature? I'll bet that your definition will either be (1) syntactic, in which case you're confusing syntax and semantics; or (2) so ambiguous as to be useless; or (3) in agreement with mine. > Compose has a simple mathematical definition, and since Dan is so proud > of his math, he surely knows that (f o g) o h = f o (g o h). > (Strangely he expressed confusion over a nested call to compose in a > posting made by someone else some time ago, but this is really quite > elementary.) *** NOTE ADDED 3/27/91: The ``confusion'' is my quote ``What are you talking about'' when faced with a nonsensical nested compose(). See the article quoted at the end of this one. That call was improperly formed and nonsensical as both a mathematical expression and a C language expression. [ composing three functions in a row ] > Let's see Bernstein's compose function do that. *** NOTE ADDED 3/27/91: This is the first time Doug implied that my compose() didn't work as advertised. Are you shooting from the hip, or are you simply confused? It is trivial to compose() twice in a row. > (On a related note, > he also claimed that it is just as easy to prove program correctness in > C as it is in a functional language. Well, no, that's not really what I claimed, but I'll let this slide. > Since his implementation of compose > in C doesn't obey one of the most trivial identities for that function, > I wonder how he reaches that bizarre conclusion.) You are simply confused. > P.S. Dan, read _The_Structure_and_Interpretation_of_Programming_Languages_, > by Abelson, Sussman and Sussman. Jim Giles said he didn't learn > anything useful from that book, but I certainly did and you might too. I second Jim's opinion. > At the very least it will show you what you can do with first-class > functions. (A short preview: blocks, delayed evaluation, > call-by-name, own variables, coroutines, non-local exits and > objects for OOP.) Ah! Finally you come down out of the fluff and get to some real issues. As I noted in the previous article, I have found very little use for first-class functions in real-world problems. All of the applications you mention can easily be handled in C---and some of them, such as coroutines and so-called ``objects,'' simply don't gain anything from first-class functions. ---Dan Path: kramden.acf.nyu.edu!brnstnd From: brnstnd@kramden.acf.nyu.edu (Dan Bernstein) Newsgroups: comp.lang.misc Subject: Re: On whether C has first-class composable functions Message-ID: <6828:Feb906:14:3491@kramden.acf.nyu.edu> Date: Sat Feb 9 06:14:34 GMT 1991 References: <1991Feb7.150537.9257@spool.cs.wisc.edu> <25199:Feb801:33:1191@kramden.acf.nyu.edu> <1991Feb8.191014.6430@spool.cs.wisc.edu> Organization: IR Lines: 96 In article <1991Feb8.191014.6430@spool.cs.wisc.edu> quale@picard.cs.wisc.edu (Douglas E. Quale) writes: > In article <25199:Feb801:33:1191@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: > >I chose the subject line (I choose most subject lines in comp.lang.misc > >these days) and I was using ``L has X'' to mean ``X can be implemented > >in L'' where L is a language and X is a semantic feature. Apparently > This is not the meaning of ``has''. X can be implemented in L is a > meaningless statement for any languages that are Turing equivalent. First of all, most real languages are not equivalent to Turing machines. People commonly use one of two models for programs. The first says, roughly, that a program is valid if its memory use is bounded by a fixed amount over all possible inputs. (This is for people who don't worry about running out of memory.) The second says, roughly, that a program is valid if its memory use is between N and N+K for all inputs, where N depends on the program and K does not. (This is for when you are worrying about running out of memory.) Both models suffice for real languages. Neither model allows a Turing machine. That's why ``has'' does distinguish languages that have, e.g., dynamic allocation from languages that don't. Second, you didn't respond to my challenge to provide a useful definition of ``L has X'' for L a language and X a semantic feature. I claim that my definition is (1) unambiguous and (2) useful. Why do I say it's useful? Because ``has'' is a helper word. Sure, the statement ``C has first-class functions'' (meaning ``first-class functions can be implemented in C'') doesn't say much. But you can qualify it! You can say ``C has efficient first-class functions'' (``first class functions can be implemented efficiently in C'') or ``C has easy-to-use first-class functions'' or ``C has easy-to-implement first-class functions.'' > Meaningless terminology is not useful, Nevertheless, it has been defined for the purposes of this discussion, so it is no longer meaningless in context. > and quite frankly Dan, I challenge > you to give me evidence that _anyone_ uses ``has'' in the sense(lessness) > that you do. Webster's, definition 5c(b): ``exercise.'' Their example: ``have mercy on us.'' ``Mercy'' is a trait---a semantic feature. ``Doug Quale has mercy on us'' means that you stop rehashing every little bit of a dead discussion---uh, I mean, that Doug Quale exercises mercy, i.e., Doug combines his primitive operations to implement mercy. ``Doug has mercy upon you'' doesn't mean that mercy is one of Doug's *basic* traits, or that mercy is defined as part of Dougginess, or that Doug *always* exercises mercy, or that Doug can show mercy without outside help; similarly for ``C has dynamically allocatable functions.'' And, before you post some irrelevant quibble, let me point out that this definition of ``has'' can be applied to impersonal, inactive objects: ``inetd.conf has control over your connections.'' > I don't think I can say anything more about this. Then don't. > >That call was improperly formed and nonsensical as both a mathematical > >expression and a C language expression. > Dan, wtf are you talking about?? You referred to the time when I expressed confusion over the supposed meaning of somebody's nested compose() call. In case you don't remember, the call in question tried to compose the compose function with an integer function. Once again, that call was improperly formed and nonsensical as both a mathematical expression and a C language expression. > square o square o square > is perfectly sensible as a mathematical expression. Yes. [ about the square examples again ] > And yes, Dan, I specifically request you to try explain what is nonsensical > about those expressions. I never said that those expressions were nonsensical. Your implication is a lie, plain and simple. I doubt you have the integrity to review the articles and apologize, but I'll give you one chance to do so before I start quoting things in public. > Instead of continually saying it's trivial, post your compose code in C and > then we'll see how it stacks up. I did. Since you apparently would rather flame than think, here's the three-way composition that you claim to be so difficult. I've written it out step-by-step and put in comments just for you. compose(square,square,sqsq) /* put square o square in sqsq */ compose(square,sqsq,sqsqsq) /* put square o sqsq in sqsqsq */ printf("%d\n",apply(sqsqsq,2)); /* apply sqsqsq to 2 and print it */ Exercise: write the missing struct fun definitions and initializations. ---Dan Path: kramden.acf.nyu.edu!brnstnd From: brnstnd@kramden.acf.nyu.edu (Dan Bernstein) Message-ID: <13759:Jan800:19:2391@kramden.acf.nyu.edu> Date: Tue Jan 8 00:19:23 GMT 1991 Newsgroups: comp.lang.misc Subject: Re: Re^2: On whether C has first-class composable functions References: <442@data.UUCP> <4408:Jan421:44:3391@kramden.acf.nyu.edu> <443@data.UUCP> Organization: IR In article <443@data.UUCP> kend@data.UUCP (Ken Dickey) writes: > SCHEME also permits the treatment of functions as full flegded data > objects; they may be passed as arguments, returned as values, made > part of composite data structures, and notated as independent, unnamed > ("anonymous") entities. {Contrast this with most ALGOL-like > languages, in which a function can be written only by declaring it and > giving it a name; imagine being able to use an integer value only by > giving it a name in a declaration!). ``Full-fledged data objects,'' yes; but ``first-class'' doesn't mean ``full-fledged.'' > More recently, [Kent Dybvig, "The Scheme Programming Language", > Prentice Hall, 1987] > ...procedures are not always named. Instead, procedures are > first-class data objects similar to strings or numbers; identifiers > are bound to procedures in the same way they are bound to other > objects. Okay, that'd do it; but if that's the definition of ``first-class'' then you can have first-class objects that you can't pass as function arguments! I don't think any of us agree with that. Anyone want to contribute more definitions? > > > By the way, what function would "apply(compose(compose,f),x);" return in C? > > > Strike "composable"? > > What are you talking about? [ explanation ] Okay, you're saying that you want compose() to apply to the first argument of a function with many arguments. This would be more useful if you also had a way to switch around the arguments to a function--- e.g., to convert f(x,y) to g(y,x). There's no reason that these things can't be done with exactly the same techniques as the one-argument compose(), so I don't think your example is a reason to say that we're not talking about composable functions. ---Dan