[comp.lang.misc] The powerlessness of Lisp

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/21/91)

In article <1991Mar20.192606.29608@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>   ... even if compile times were instant I'd spend forever just
>   waiting for most programs to run.
> Based on my experience, this is nonsense.  I develop AI applications
> in Common Lisp that do complex things like understand natural language
> utterances and reason about how best to design graphical
> representations of information, and these programs run fairly quickly,
> i.e. fast enough to act as an interface to another program.

Wow. So you have a naturally complex but short-running program. I admit
such programs exist. They are not the mainstream, at least not in
systems programming and numerical programming.

>   A machine is much more than its ``primitive datatypes.'' But Lisp
>   doesn't even provide full access to pointers.
> What does this mean?  "Pointers" are an artifact of languages like C,

Be serious. Pointers (a.k.a. addresses) have been in every machine
language at least since 1960.

C provides a concept of ``memory'' (more precisely, the set of all
pointer values, which equals the set of all char pointer values modulo
typechecking) and pointers into memory. You can do things with memory in
C that you CANNOT even express in Lisp. To return to the original point,
C is more powerful than Lisp in this area.

>   In fact, I've been focusing on the prototyping and development stage
>   of a program, because that's when it's most important to get good
>   compile times *and* run times.
> As someone who has worked in a C shop in another life, building
> business applications, I can say that there's no comparison between the
> two with respect to development time or maintainability of code.

And I can say that the continued refusal of dynamic-typing advocates to
actually *make* such a comparison objectively is one mark of a true
religion.

---Dan

quale@khan.cs.wisc.edu (Douglas E. Quale) (03/21/91)

In article <4637:Mar2102:11:2991@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>typechecking) and pointers into memory. You can do things with memory in
>C that you CANNOT even express in Lisp. To return to the original point,

Examples, please.

-- Doug Quale
quale@khan.cs.wisc.edu

cs450a03@uc780.umd.edu (03/22/91)

Dan Bernstein writes:
>And I can say that the continued refusal of dynamic-typing advocates to
>actually *make* such a comparison objectively is one mark of a true
>religion.

Come on, Dan, what's an "objective" comparison?

The only sort of case I know of where a program is written to the same
spec in a number of different languages is class projects.  And in
that case there is very little in the way of a maintenance problem.
Nor is speed much of a consideration.

Just for the record, for the class that I have this account, my term
project took about an hour to write, and the source listing and a
sample run fit on a single page.  That's with comments.  (My prof,
never having seen the language before, was able to understand pretty
well what each step was doing, simply from the comments and the form
of the statements).

Other people, struggling with constructing parsers and symbol tables
and so on took longer.

But is this objective?  

Raul Rockwell

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/25/91)

In article <1991Mar21.123512.22876@daffy.cs.wisc.edu> quale@khan.cs.wisc.edu (Douglas E. Quale) writes:
> In article <4637:Mar2102:11:2991@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >typechecking) and pointers into memory. You can do things with memory in
> >C that you CANNOT even express in Lisp. To return to the original point,
> Examples, please.

p + i, as I already pointed out. You can find higher-level applications
(e.g., byte-copying into a character buffer, which can then be written
portably to disk and read back later) for yourself.

Other points: GNU Emacs *is* written in C, with only a small amount of
``helper'' code to implement dynamic typing. Yes, this *does* provide
all the perceived advantages of a dynamically typed language like Lisp,
and in this case makes most of the resulting program look like Lisp. The
total cost is that bit of helper code.

Doug, you have made nothing of yourself in this newsgroup but a nuisance
for at least the last few months. I post a working compose() in C, for
example, and you have to insist in five separate articles that it
doesn't work when nested. You challenge references rather than spending
a few minutes to educate yourself; you repeatedly bring up dead issues
and ignore arguments and logic that you don't like; most importantly,
you apparently don't *want* to contribute. Why do you post at all?

---Dan

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/26/91)

In article <1991Mar21.155528.6068@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>     [in response to my description of some complex and fast Lisp programs]
>   Wow. So you have a naturally complex but short-running program. I
>   admit such programs exist. They are not the mainstream, at least not
>   in systems programming and numerical programming.
> What does "short-running" mean?

What I meant was that the program doesn't run for a significant amount
of time. (This obviously implies that the run time of the program
doesn't matter, so inefficient code is reasonable.) ``Short'' and
``significant'' are subjective, of course, and depend on the situation
at hand.

I claim that run time is, overall, a significant percentage of
turnaround time during the development and maintenance of most programs.
Since programs in Lisp are often several times slower than the same
programs in C, Lisp significantly slows down program development, all
else being equal.

So it's not worth programming in Lisp unless all else is not equal---i.e.,
unless Lisp significantly reduces the number of test runs, or the pain of
maintenance. See below.

>   Be serious. Pointers (a.k.a. addresses) have been in every machine
>   language at least since 1960.
> So have conditional jumps.  What's the point?  If you want to program
> in machine language, do it.

But almost everything that people do with jumps can be expressed with
if/loop/break---and the exceptions or perceived exceptions have been
enough to keep an unstructured jump in every popular language.

In contrast, people want to do things with memory that they can't do in
Lisp. C *is* more powerful than Lisp in this respect.

> I don't want to have to know about the underlying architecture, and
> you seem to want to program at that level, which explains why you like
> Machine Independent Machine Language (aka C).

I don't want to have to know about the underlying architecture either.
I'm glad that C provides a powerful yet portable model of almost all
existing hardware architectures. It's a shame that Lisp doesn't.

  [ returning to... ]
>   As someone who has worked in a C shop in another life, building
>   business applications, I can say that there's no comparison between
>   the two [C and Lisp] with respect to development time or
>   maintainability of code. 

That's not objective. Where are the examples? Where are the brilliant
rewrites of statically typed code into dynamically typed code of a
fraction of the length? Every example people give seems to depend almost
entirely on the strength of available libraries. I'm all in favor of
good libraries, but what does that have to do with dynamic typing?
To return to my favorite example along these lines: Perhaps 1% of the
GNU Emacs code is responsible for implementing dynamic typing in C; if
it were all written in Lisp instead, it'd be about 99% of the original
length. Where are the savings?

---Dan
De syntactic gustibus non disputandum est.

bbc@rice.edu (Benjamin Chase) (03/26/91)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:

>Other points: GNU Emacs *is* written in C, with only a small amount of
>``helper'' code to implement dynamic typing.

"GNU Emacs" is roughly 1/2 C and 1/2 elisp.

Or did you mean just that file of machine code that gets run when you
start gnu emacs?  No, even that small part of GNU Emacs wasn't derived
solely from C.

Get some facts, Dan.
--
	Ben Chase <bbc@rice.edu>, Rice University, Houston, Texas

oz@yunexus.yorku.ca (Ozan Yigit) (03/26/91)

In article <16060:Mar2515:41:5691@kramden.acf.nyu.edu> Dan Bernstein writes:

>Doug, you have made nothing of yourself in this newsgroup but a nuisance
>for at least the last few months.

I would dare say that this net has seen only one serious nuisance in the
last little while, and that one has been posting from
brnstnd@kramden.acf.nyu.edu.

>You challenge references rather than spending a few minutes to
>educate yourself;

Look who is talking.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/26/91)

In article <BBC.91Mar25115827@libya.rice.edu> Benjamin Chase <bbc@rice.edu> writes:
> Or did you mean just that file of machine code that gets run when you
> start gnu emacs?  No, even that small part of GNU Emacs wasn't derived
> solely from C.

Yes, that is the GNU Emacs program, and I never said anything about what
it was ``derived from.'' It is written in C, and any C programmer who
wants to make use of dynamic typing can get away with a similarly tiny
amount of helper code. No amount of crap about ``sole derivations'' or
``it's written in Lisp, really!'' will change this fact.

What are you trying to do? Make a religious point, or get work done? I'm
sure RMS didn't care about how impossible polymorphic lists are in C
when he was working on Emacs.

> Get some facts, Dan.

Sheesh. At least I've had the sheer joy of compiling Emacs on a couple
of unsupported systems, one of which can't handle undumping. I'm not an
Emacs expert, but you can assume that I know what language a program is
written in when I've worked with the code of that program.

---Dan

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/26/91)

In article <22144@yunexus.YorkU.CA> oz@yunexus.yorku.ca (Ozan Yigit) writes:
> In article <16060:Mar2515:41:5691@kramden.acf.nyu.edu> Dan Bernstein writes:
> >Doug, you have made nothing of yourself in this newsgroup but a nuisance
> >for at least the last few months.
> I would dare say that this net has seen only one serious nuisance in the
> last little while, and that one has been posting from
> brnstnd@kramden.acf.nyu.edu.

I understand: It's a ``nuisance'' when someone refuses to accept the
dogma of current computer science. Sorry, folks, but sorting is linear
in the number of bytes, and you can implement composable functions in C,
and you can solve the halting problem in practice, and C has more
powerful pointer handling than Lisp. If you think it's a nuisance when
someone tells the truth as he sees it, then yes, folks, I guess I'm
Ozan's sort of nuisance.

Unlike Ozan, I don't see rational disagreement as a problem. The problem
in this group is the failure of people to try to see past differences in
terminology and stick to technical issues. Articles like Ozan's---like
this one, or almost any from Jim Giles---should be lost in the flood of
useful discussions about what can be done with various language features
and what should appear in future languages. I still wish it were
possible to start a conversation here about pointers and arrays without
having it degenerate into a series of religious arguments. It's not.

Except for the ``contributions'' from Ozan and Doug, I've found the
recent threads here quite useful. I only hope that this can continue
into future discussions.

---Dan

cs450a03@uc780.umd.edu (03/26/91)

Dan Bernstein writes:
>p + i, as I already pointed out. You can find higher-level applications
>(e.g., byte-copying into a character buffer, which can then be written
>portably to disk and read back later) for yourself.

Any reason you can't call the buffer an array?  *(p + i) is array
addressing.

>Other points: GNU Emacs *is* written in C, with only a small amount of
>``helper'' code to implement dynamic typing.

I think the small amount of code it takes to implement dynamic typing
should count as a win for dynamic typing.  As should the large amount
of code which was written using it.

You might argue that LISP is used because it is easy to change, not
because of its runtime type-checking, but the two features work
together.

Raul Rockwell

cs450a03@uc780.umd.edu (03/26/91)

Dan Bernstein writes:
>But almost everything that people do with jumps can be expressed with
>if/loop/break---and the exceptions or perceived exceptions have been
>enough to keep an unstructured jump in every popular language.

Or if you want to get real fancy, you can put a case statement in a
while loop.  Wonderful way to spaghetti code.  [Just an aside, not why
I'm posting.]

>Where are the examples? Where are the brilliant rewrites of
>statically typed code into dynamically typed code of a fraction of
>the length?

Well... now that I've admitted that I've heard of APL...  

I remember a presentation by this economics professor, where he was
implementing some nasty partial differential model of some theory.  He
had had this team of FORTRAN writers working on it for something like
6 months, and after generating something on the order of 20-50,000
lines of code they gave up.

First pass at writing it in APL was something like 20 pages of code.
In the presentation he had it down to three, and claimed that he could
see further improvements that would take it down to even less.  (His
estimate was that it would get down to about a page).  He also said
that the FORTRAN team would be able to implement his model, now that
they had something to base their work on.

I don't remember much more than that, this was around 87-88, and at
the time I was more interested in trying to figure out what the
variables in the model stood for than I was in the code.

By the way, please don't try and claim that APL has a better math
library than FORTRAN.  You'll upset a whole bunch of dusty deckers ;-)

Raul Rockwell

fnwlr1@acad3.alaska.edu (RUTHERFORD WALTER L) (03/26/91)

In article <21189:Mar2521:55:0691@kramden.acf.nyu.edu>, brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes...

> 
>I understand: It's a ``nuisance'' when someone refuses to accept the
>dogma of current computer science.
   [examples of the truth a'la Dan Bernstein deleted to save space]
>someone tells the truth as he sees it, then yes, folks, I guess I'm
>Ozan's sort of nuisance.
> 

Only when the truth as you see it includes statements like:

  >Doug, you have made nothing of yourself in this newsgroup but a nuisance
  >for at least the last few months.                                     


>and what should appear in future languages. I still wish it were
>possible to start a conversation here about pointers and arrays without
>having it degenerate into a series of religious arguments. It's not.
                                       ^^^^^^^^^^^^^^^^^^^
Would you please come up with a better phrase for the types of
"conversations" which erupt here?  You'll give religion a bad name.  :-)


---------------------------------------------------------------------
      Walter Rutherford
       P.O. Box 83273          \ /    Computers are NOT intelligent;
   Fairbanks, Alaska 99708    - X -
                               / \      they just think they are!
   fnwlr1@acad3.alaska.edu
---------------------------------------------------------------------

gudeman@cs.arizona.edu (David Gudeman) (03/26/91)

In article  <16521:Mar2516:10:0791@kramden.acf.nyu.edu> Dan Bernstein writes:
]Where are the examples? Where are the brilliant
]rewrites of statically typed code into dynamically typed code of a
]fraction of the length? Every example people give seems to depend almost
]entirely on the strength of available libraries...
]but what does that have to do with dynamic typing?

Dynamic typing encourages re-usability of code, thereby leading to
much more powerful libraries with fewer primitives.

]To return to my favorite example along these lines: Perhaps 1% of the
]GNU Emacs code is responsible for implementing dynamic typing in C; if
]it were all written in Lisp instead, it'd be about 99% of the original
]length. Where are the savings?

That's bogus.  You haven't taken into account all the redundant code
that does slightly different things, or all the declarations.
--
					David Gudeman
gudeman@cs.arizona.edu
noao!arizona!gudeman

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/26/91)

In article <1991Mar25.210406.9384@linus.mitre.org> john@clouseau.mitre.org (John D. Burger) writes:
  [ on ``short-running'' ]
> Huh?  I don't understand this at all; your implication is not obvious
> to me.  Anyway, as I said, the Lisp programs I'm referring to run for
> hours/days at a time.  Is that long enough to be significant?

You said it was ``fast enough,'' so obviously its run time is not
particularly significant. I claim that for most programs the opposite is
true, and dynamic typing can greatly increase the turnaround time during
development. You can measure the accuracy of this claim by dividing the
CPU time of test runs by the total programming time, for various
programs.

>   So it's not worth programming in Lisp unless all else is not
>   equal---i.e., unless Lisp significantly reduces the number of test
>   runs, or the pain of maintenance. See below.
> All else isn't equal, as is usually the case when people say that.
> Lisp gives you heterogenous collections, incremental compilation, a
> REAL source level debugger, and lots more.  That's why development in
> Lisp IS significantly faster.

A ``REAL source level debugger'' and incremental compilation are
functions of the environment. Heterogeneous collections don't seem to be
used in real applications---or do you have a counterexample?

>   ... e.g., byte-copying into a character buffer, which can then be
>   written portably to disk and read back later ...
> This can be done in Lisp.

No. You can use a list to simulate the buffer, but you cannot do the job
as stated. You can construct other examples where Lisp's lack of pointer
arithmetic or byte-oriented memory shows through.

>   I'm glad that C provides a powerful yet portable model of almost all
>   existing hardware architectures.  It's a shame that Lisp doesn't.
> It's not clear to me that it doesn't, but anyway, I don't want to
> model hardware, I want to model the problems I need to solve.

Huh? Are you not trying to write programs so that machines can run them?

> I find your example, and others like it, much more compelling than any
> rewrite examples.  Why do you think it was deemed necessary to
> implement dynamic typing in C for GNU Emacs?  Why do you think X
> Windows effectively implements dynamic typing for interface entities,
> not to mention a run time interpreter?
  [ etc. ]

``Why do you think people write libraries and use them?'' Because it's
easier to use a library than to rewrite its code. Can we apply your
logic to insist that all library routines should be part of every
language?

The point is that someone who wants to use dynamic typing in C can
easily do so. I believe we agree here. So what is gained by including
dynamic typing in the language (hence compiler), rather than in a
standard library? The obvious disadvantage is that most existing
dynamically typed languages *force* you to use dynamic typing, and don't
let you declare types even when you know what they will be.

---Dan

new@ee.udel.edu (Darren New) (03/26/91)

In article <27234:Mar2603:13:2991@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>[...] Heterogeneous collections don't seem to be
>used in real applications---or do you have a counterexample?

Please be sure to see the article I've already posted in which
I give three examples of where I have used hetrogeneous lists.
(Since this is your third posting asking for that list, I just
wanted to make sure you saw it :-)
	-- Darren

-- 
--- Darren New --- Grad Student --- CIS --- Univ. of Delaware ---
----- Network Protocols, Graphics, Programming Languages, 
      Formal Description Techniques (esp. Estelle), Coffee, Amigas -----
  +=+=+ My time is very valuable, but unfortunately only to me +=+=+

oz@yunexus.yorku.ca (Ozan Yigit) (03/26/91)

In article <see ref if you care> Dan Bernstein writes(?):

>I understand: It's a ``nuisance'' when someone refuses to accept the
>dogma of current computer science.

It is a nuisance when ignorance and refusal to learn is glorified as the
refusal of some would-be dogma.

>Unlike Ozan, I don't see rational disagreement as a problem.

You never have rational disagreements. That is the problem.

oz
---
We only know ... what we know, and    | Internet: oz@nexus.yorku.ca 
that is very little. -- Dan Rather    | UUCP: utzoo/utai!yunexus!oz

cs450a03@uc780.umd.edu (03/26/91)

Walter Rutherford writes:
> [Dan Bernstein writes:]
>>having it degenerate into a series of religious arguments. It's not.
>                                       ^^^^^^^^^^^^^^^^^^^
>Would you please come up with a better phrase for the types of
>"conversations" which erupt here?  You'll give religion a bad name.  :-)

How about "The Spanish Inquisition"?  ;-)

Er... The Static Inquisition???  Nah... doesn't have the right ring...

Raul Rockwell

quale@saavik.cs.wisc.edu (Douglas E. Quale) (03/27/91)

In article <16060:Mar2515:41:5691@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>> >typechecking) and pointers into memory. You can do things with memory in
>> >C that you CANNOT even express in Lisp. To return to the original point,
>> Examples, please.
>
>p + i, as I already pointed out. You can find higher-level applications
>(e.g., byte-copying into a character buffer, which can then be written
>portably to disk and read back later) for yourself.

Unfortunately, Dan, p + i is not a program in C or any other language I
know, and I can get the equivalent effect with a null lisp program.
Byte copying is trivial in Common Lisp.  Big Deal.  As far as portability goes,
CL is much more portable than C because it insulates the program from
differences in word size and other low level machine details.  A typical
"portable" C program running on n different platforms is usually n different
programs selected by conditional compilation via #ifdef's.

>
>Other points: GNU Emacs *is* written in C, with only a small amount of
>``helper'' code to implement dynamic typing. Yes, this *does* provide
>all the perceived advantages of a dynamically typed language like Lisp,
>and in this case makes most of the resulting program look like Lisp. The
>total cost is that bit of helper code.
>

Emacs is written in elisp.  Richard Stallman has explained why Emacs *can't*
be written in C.  The major advantage of lisp over C here is the fact that
lisp is much more easily extensible.  You are the only person I have ever
heard claim that Emacs is written almost entirely in C.  I don't wonder why.

>
>Doug, you have made nothing of yourself in this newsgroup but a nuisance
>for at least the last few months. I post a working compose() in C, for
>example, and you have to insist in five separate articles that it
>doesn't work when nested. You challenge references rather than spending
>a few minutes to educate yourself; you repeatedly bring up dead issues
>and ignore arguments and logic that you don't like; most importantly,
>you apparently don't *want* to contribute. Why do you post at all?
>
>---Dan

Actually Dan, I don't post nearly as often in this group as do you because
although I almost invariably disagree with everything you post here, apparently
so does just about everyone else.  (Oddly enough I have much greater sympathy
for your arguments in other news groups.  I don't post there because I
generally don't have anything to add, and often they are matters outside my
area of expertise.  Your posting of compression sources and related discussion
is excellent, the algorithm descriptions very clear and the discussion on
copyrights taught me several important things.)  I follow the discussion,
remaining silent until you make a particularly outrageous claim, or something
important seems to have been overlooked.  More of my postings are sparked by
the former than the latter because you are quite outrageous and folks here on
this newsgroup are quite thorough.

* I only challenge references when I believe they don't exist.  If you don't
* have any personal experience with a particular problem  and don't have any
* knowledge of the relevant literature, don't claim to.

I am amused that you are annoyed that I called you out on Emacs, 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 think
you can't provide any such references because I don't believe you have read any
of the literature.  (I also doubt that there's very much of it to support your
fairly unique point of view anyway.)  If you have such references, post them.
I don't need an exact reference.  If you give me the name of the journal and an
approximate date and title I can look it up.

As for compose, your response was repeatedly, "I posted it last month, I posted
it last year, My mother posted it last year...." ad nauseum.  If you really had
the stuff, prove it.  Continually saying something is trivial is not evidence.

Dan, you are a master of evasion.  You claim to have personal experience with
Common Lisp which I doubt. You also claim to have read literature supporting a
viewpoint that I haven't seen in the literature and I doubt you there as well.
You bristle when asked for any evidence that what you're saying isn't just
hot air.  If you had the evidence you wouldn't have to bristle.

Time to stand and deliver.

(I expect another evasion.)

-- Doug Quale
quale@saavik.cs.wisc.edu

john@mingus.mitre.org (John D. Burger) (03/27/91)

We seem to have a vocabulary problem regarding program speed.
Regarding some Lisp programs that I described,

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:

  You said it was ``fast enough,'' so obviously its run time is not
  particularly significant. I claim that for most programs the
  opposite is true, and dynamic typing can greatly increase the
  turnaround time during development. You can measure the accuracy of
  this claim by dividing the CPU time of test runs by the total
  programming time, for various programs.

I still don't understand this.  The run time is significant.  Period.
The program is not too slow.  If I could have implemented it in a
statically typed language, it would almost certainly run faster.  But
I contend that development time in that case would have been nearly
infinite.

As far as your measurements go, I haven't run any such experiments,
and neither has anyone else.  But you know that.  Again, in my
experience, which is real, development in Lisp and other
dynamically-typed languages is faster than the alternatives.  Point
blank, have you ever developed any significant program in Lisp?

Concerning the pluses of Lisp, Dan continues:

  A ``REAL source level debugger'' and incremental compilation are
  functions of the environment.

Fine. Then the distribution of languages with these features should be
independent of whether those languages have dynamic typing.  This
doesn't appear to be the case, however.

  Heterogeneous collections don't seem to be used in real applications
  ---or do you have a counterexample?

Several examples have already been given by others.  Frankly, I don't
see how "real applications" (whatever that means) can do without
heterogeneity.  How would you represent logical formulae?  A predicate
has a name and a collection of arguments: some are variables, some are
constants, some are function terms.  A logical connective has a set of
arguments, some of which are other logical connectives, and some of
which are relational expressions.

How about a drawing program, in which you need to represent sets of
polygons, splines, bitmaps, and so on?

Even simpler, how about a calculator, doing arithmetic with integers,
reals, ratios and complex numbers?

The world is full of heterogeneous collections.  I think people who
don't see any use in representing them are simply making a virtue of
necessity.

Concerning your "byte-copying" example, you don't appear to actually
know Common Lisp.  Additionally, your example seems to hinge on the
fact that C represents characters as 1-byte integers.  But then again,
C represents practically everything that way.

  The point is that someone who wants to use dynamic typing in C can
  easily do so. I believe we agree here.

The point is that lots of people feel they have to implement dynamic
typing in C.  Doesn't that tell you something?  But anyway, we agree
in the sense that, yes, dynamic typing can be implemented in C, but
ORTHOGONALLY TO THE EXISTING TYPE SYSTEM.  I can put a TYPE field in
each of my structures, and then dispatch on its value at runtime, but
I can't declare at compile time that a particular structure will have
a particular TYPE value.  The NIH Class Library for C++ is a good
example of this.  In order to get runtime typing, they've had to
implement a SECOND type system on top of the first one, and never the
twain shall meet.

  So what is gained by including dynamic typing in the language (hence
  compiler), rather than in a standard library?  The obvious
  disadvantage is that most existing dynamically typed languages
  *force* you to use dynamic typing, and don't let you declare types
  even when you know what they will be.

This just isn't the case.  Lisp (and most other dynamically-typed
languages) let you declare types all you want, and most Lisp compilers
pay attention and produce significantly smaller/faster code.  The
situation you describe is exactly what's wrong with YOUR way of doing
dynamic typing, i.e. as an add on.  The compiler can't know about it,
and therefore can't optimize it.
--
John Burger                                               john@mitre.org

"You ever think about .signature files? I mean, do we really need them?"
  - alt.andy.rooney

gudeman@cs.arizona.edu (David Gudeman) (03/27/91)

In article  <1991Mar26.165516.13035@daffy.cs.wisc.edu> Douglas E. Quale writes:
]...Byte copying is trivial in Common Lisp...

Still, Dan's point is valid.  There _are_ machine-level things you can
do in low-level languages that you can't do in Common Lisp, if for no
other reason than because Common Lisp has to protect its tags for
storage management.

It is also the case that pointer-like operations in Common Lisp are
less efficient than pointer operations in C.  For example array
indexing usually involves a type check, a range check, and an extra
offset or two.  This can be a problem since a lot of the time
efficiency is the main reason for using pointers.
--
					David Gudeman
gudeman@cs.arizona.edu
noao!arizona!gudeman

peter@ficc.ferranti.com (Peter da Silva) (03/27/91)

In article <27234:Mar2603:13:2991@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> Heterogeneous collections don't seem to be
> used in real applications---or do you have a counterexample?

Symbol tables.
-- 
Peter da Silva.  `-_-'  peter@ferranti.com
+1 713 274 5180.  'U`  "Have you hugged your wolf today?"

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/27/91)

In article <1991Mar26.172536.12178@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>   You said it was ``fast enough,'' so obviously its run time is not
>   particularly significant. I claim that for most programs the
>   opposite is true, and dynamic typing can greatly increase the
>   turnaround time during development. You can measure the accuracy of
>   this claim by dividing the CPU time of test runs by the total
>   programming time, for various programs.
  [ ... ]
> As far as your measurements go, I haven't run any such experiments,
> and neither has anyone else.  But you know that.

On the contrary. Often I spend a considerable length of time working on
just one program. After the fact I have accounting records and various
other logs to look at, and it makes perfect sense to total up the time
spent running the program and divide it by the real time spent in that
session.

> Point
> blank, have you ever developed any significant program in Lisp?

What does ``significant'' mean? More than 10000 lines? No.

>   A ``REAL source level debugger'' and incremental compilation are
>   functions of the environment.
> Fine. Then the distribution of languages with these features should be
> independent of whether those languages have dynamic typing.  This
> doesn't appear to be the case, however.

Huh? The Forth environments I've worked with have incremental
compilation, and Saber-C provides a far superior debugging environment
to anything I've seen for Lisp. Shall I conclude that static typing
helps debugging?

>   Heterogeneous collections don't seem to be used in real applications
>   ---or do you have a counterexample?
  [ ... ]
> How would you represent logical formulae?  A predicate
> has a name and a collection of arguments: some are variables, some are
> constants, some are function terms.

Sounds like a union type to me.

> Concerning your "byte-copying" example, you don't appear to actually
> know Common Lisp.  Additionally, your example seems to hinge on the
> fact that C represents characters as 1-byte integers.

Obviously you misunderstood. Yes, the example *does* depend on the fact
that C regards all of memory as character-addressible. This is exactly
why the example *can't* be handled in Lisp.

>   The point is that someone who wants to use dynamic typing in C can
>   easily do so. I believe we agree here.
> The point is that lots of people feel they have to implement dynamic
> typing in C.  Doesn't that tell you something?

Lots of people feel they have to implement string functions in C.
Doesn't that tell you something? It tells me that the string functions
belong in a standard library. It sure doesn't tell me that the compiler
should grok strings.

> But anyway, we agree
> in the sense that, yes, dynamic typing can be implemented in C, but
> ORTHOGONALLY TO THE EXISTING TYPE SYSTEM.
  [ and orthogonality must imply that: ]
> The compiler can't know about it,
> and therefore can't optimize it.

Oh? How come C++ is optimized quite reasonably even though it's commonly
implemented as an orthogonal layer over C? How come so many of the
dynamic typing optimizations reduce to good inlining and data flow
heuristics---things that don't require the compiler to understand what
you're doing?

If your argument were true, then converting, say, X Windows to a
dynamically typed language would speed it up. After all, the dynamic
typing would be part of the compiler, and that *must* produce better
optimization than an orthogonal system, right? So how come programs in
dynamically typed languages are so slow?

---Dan

peter@ficc.ferranti.com (Peter da Silva) (03/28/91)

In article <1991Mar26.172536.12178@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
>   A ``REAL source level debugger'' and incremental compilation are
>   functions of the environment.

> Fine. Then the distribution of languages with these features should be
> independent of whether those languages have dynamic typing.  This
> doesn't appear to be the case, however.

Just for the hell of it, let me point out that the two languages that
have the greatest number of units out with these features *are* statically
typed: Forth and Basic.
-- 
Peter da Silva.  `-_-'  peter@ferranti.com
+1 713 274 5180.  'U`  "Have you hugged your wolf today?"

john@mingus.mitre.org (John D. Burger) (03/28/91)

In article <7988:Mar2700:09:2691@kramden.acf.nyu.edu> 
>In article <1991Mar26.172536.12178@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
>> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>>   You said it was ``fast enough,'' so obviously its run time is not
>>   particularly significant. I claim that for most programs the
>>   opposite is true, and dynamic typing can greatly increase the
>>   turnaround time during development. You can measure the accuracy of
>>   this claim by dividing the CPU time of test runs by the total
>>   programming time, for various programs.
>  [ ... ]
>> As far as your measurements go, I haven't run any such experiments,
>> and neither has anyone else.  But you know that.
>
>On the contrary. Often I spend a considerable length of time working on
>just one program. After the fact I have accounting records and various
>other logs to look at, and it makes perfect sense to total up the time
>spent running the program and divide it by the real time spent in that
>session.
>
>> Point
>> blank, have you ever developed any significant program in Lisp?
>
>What does ``significant'' mean? More than 10000 lines? No.
>
>>   A ``REAL source level debugger'' and incremental compilation are
>>   functions of the environment.
>> Fine. Then the distribution of languages with these features should be
>> independent of whether those languages have dynamic typing.  This
>> doesn't appear to be the case, however.
>
>Huh? The Forth environments I've worked with have incremental
>compilation, and 
>
>>   Heterogeneous collections don't seem to be used in real applications
>>   ---or do you have a counterexample?
>  [ ... ]
>> How would you represent logical formulae?  A predicate
>> has a name and a collection of arguments: some are variables, some are
>> constants, some are function terms.
>
>Sounds like a union type to me.
>
>> Concerning your "byte-copying" example, you don't appear to actually
>> know Common Lisp.  Additionally, your example seems to hinge on the
>> fact that C represents characters as 1-byte integers.
>
>Obviously you misunderstood. Yes, the example *does* depend on the fact
>that C regards all of memory as character-addressible. This is exactly
>why the example *can't* be handled in Lisp.
>
>>   The point is that someone who wants to use dynamic typing in C can
>>   easily do so. I believe we agree here.
>> The point is that lots of people feel they have to implement dynamic
>> typing in C.  Doesn't that tell you something?
>
>Lots of people feel they have to implement string functions in C.
>Doesn't that tell you something? It tells me that the string functions
>belong in a standard library. It sure doesn't tell me that the compiler
>should grok strings.
>
>> But anyway, we agree
>> in the sense that, yes, dynamic typing can be implemented in C, but
>> ORTHOGONALLY TO THE EXISTING TYPE SYSTEM.
>  [ and orthogonality must imply that: ]
>> The compiler can't know about it,
>> and therefore can't optimize it.
>
>
>---Dan

Concerning dynamic typing and nice environments,
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:

  Saber-C provides a far superior debugging environment to anything
  I've seen for Lisp. Shall I conclude that static typing helps
  debugging?

Having used all of them, I state that Allegro Composer, Lucid's SPE
and the Symbolics Lisp Machine are all FAR superior to Saber-C.  But,
you've missed the point.  Saber-C works as well as it does because
they've implemented a version of C with dynamic typing, as well as an
interpreter.

Other people are dealing with your heterogeneous collection arguments.
Concerning your byte-copying example, again, this doesn't have
anything to do with statis or dynamic typing.  If you want to program
in portable machine code, have a ball.

  How come C++ is optimized quite reasonably even though it's commonly
  implemented as an orthogonal layer over C? How come so many of the
  dynamic typing optimizations reduce to good inlining and data flow
  heuristics---things that don't require the compiler to understand
  what you're doing?

C++ is commonly TRANSLATED to C, not implemented on top of C.  How can
a compiler do inlining if it doesn't understand what you're doing?
--
John Burger                                               john@mitre.org

"You ever think about .signature files? I mean, do we really need them?"
  - alt.andy.rooney

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/28/91)

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

barmar@think.com (Barry Margolin) (03/28/91)

In article <26146:Mar2804:56:5791@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>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.

Assuming buf was created with

(defvar buf (make-string <size>))

and <size> is large enough to hold a fixnum:

(let ((temp (make-array () :element-type 'fixnum :displaced-to buf)))
  (declare (dynamic-extent temp))
  (setf (aref temp) n))

Note, however, that this is not portable, but I'm not sure the original C
code was, either.

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

Yes, it's quite possible to write such code.  I'll bet pty is loaded with
system-dependency #ifdef's, though.  My guess is that the C world is
probably split about even between those two classes of 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.

If Emacs is implemented in C, then the shell is implemented in machine
language.  The Emacs interface that users see is written in a combination
of C (most of the character-level I/O, and the Lisp interpreter) and ELisp
(most of the commands).  Similarly, the shell is implemented in C, but the
commands that users type are implemented in a mixture of mostly C and shell
script.

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

I think this is a flawed analogy.  When dealing with the shell, we normally
distinguish the shell itself from the commands it executes (ignoring
built-in shell commands), since the commands aren't directly associated
with the shell -- if you change your search path, the command set changes.
Emacs, however, starts up with a large collection of Lisp-written commands
and functions built in, and many of them are fundamental to the operation
of the editor.  The shell will continue to run without any of the shell
scripts that people ordinarily use, but Emacs will fall flat on its face
without some of the Lisp functions.
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

quale@saavik.cs.wisc.edu (Douglas E. Quale) (03/29/91)

The original challenge was so short I'll repeat it:

In Common Lisp,

(defun compose (f g)
  (lambda (&rest) (funcall f (apply g &rest))))

I think it looks better in Scheme,

(define (compose f g)
  (lambda x (f (apply g x))))

These definitions use dynamic typing to obtain polymorphism.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

And now Dan's response:


In article <26146:Mar2804:56:5791@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>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.

Probably mail isn't working on this machine correctly.  I bear some
responsibility for that, but I am content to let the judgement of which of us
is a royal asshole to the readers of this newsgroup.

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

And Dan gives a pathetic attempt to code compose in C.

Naturally his compose is not polymorphic, a key advantage of dynamic typing
that was the whole point of this exercise.  That point was specifically
mentioned in the challenge since I figured Dan would try to worm out of it --
support for genericity is weak in C.

As a parting thought, how long is Dan's nonpolymorphic compose compared to the
fully polymorphic lisp versions?  Seems like his code is infinitely less
capable and well over three times longer.  What a surprise.

Go ahead Dan.  Thrash me in public.  You'll only make more of an ass of
yourself than you already have, if that's possible.  I'm still waiting for a
polymorphic compose in C.  That was quite clear in my post, but I'm saying it
again since you seem to have trouble with English.

-- Doug Quale
quale@saavik.cs.wisc.edu

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/29/91)

In article <1991Mar28.064405.13664@Think.COM> barmar@think.com (Barry Margolin) writes:
> Note, however, that this is not portable, but I'm not sure the original C
> code was, either.

Yes, it *is* portable in C, provided that buf is aligned as an int. I'll
grant that Common Lisp has as much pointer support as Ada---i.e., the
operations necessary to regard memory as a set of bytes was grafted on
afterwards, with so few guarantees that you cannot write portable code
in it.

> Yes, it's quite possible to write such code.  I'll bet pty is loaded with
> system-dependency #ifdef's, though.  My guess is that the C world is
> probably split about even between those two classes of programs.

Nope, none at all in pty's case, except the common idiom #ifdef BSD
#include <limits.h> #endif isolated in one include file. Everything else
is a configuration option to select among available libraries. I think
this is rather typical of both systems code and non-systems code in C.

  [ comments about whether Emacs is written in elisp or in C ]

I see your point, but, as I've said before: I refuse to admit that you
can change any fundamental characteristics of a language simply by
adding a library. Sure, the GNU Emacs distribution comes with a lot of
elisp code, without which you'd be insane to use the system. But that
elisp code is on *top* of the Emacs program. Emacs is written in C, and
no amount of library writing can change this fact.

---Dan

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/29/91)

Beautiful, Doug. You repeatedly say that my compose() doesn't nest, you
post some sort of final challenge, you accuse me of evasion, I repost
the articles in question, and now you try to escape humiliation by
perverting the issue into whether compose() can be polymorphic in C.

That last bit is evasion, Douglas. Sorry, but it won't work. The issue
back then was function composition, NOT dynamic typing. You repeatedly
shot from the hip on the issue of whether the available implementations
of compose() in C could nest. Now I've called you on it, I've quoted
articles where you made a fool of yourself, and you won't be able to
pretend that you were saying something else.

In this last article, you claim that my reposted compose() routine was
in response to your points about dynamic typing. That claim is a lie.
Since you're obviously so desperate to avoid embarassment, I can
understand your perversions; that doesn't make them the truth.

You also seem to be confusing dynamic typing with various other issues,
including function allocation. I invite you to learn Forth.

---Dan

barmar@think.com (Barry Margolin) (03/29/91)

In article <2328:Mar2819:54:2491@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
[Regarding my Lisp translation of '*(int *)&buf = n':]
>In article <1991Mar28.064405.13664@Think.COM> barmar@think.com (Barry Margolin) writes:
>> Note, however, that this is not portable, but I'm not sure the original C
>> code was, either.
>
>Yes, it *is* portable in C, provided that buf is aligned as an int. I'll
>grant that Common Lisp has as much pointer support as Ada---i.e., the
>operations necessary to regard memory as a set of bytes was grafted on
>afterwards, with so few guarantees that you cannot write portable code
>in it.

I guess we are now stuck on agreeing what "portable" means.  After
executing:

	char buf[sizeof int];
	*(int *)&buf = 1;

what is the value of buf[0]?  On some machines it will be 0, on other
machines it will be 1, and some strange machines could produce other
values.

I admit that it's *more* portable than the Lisp translation; the C code has
implementation-dependent results, whereas the Common Lisp version has
undefined consequences.  Indeed, you'll notice that my example used FIXNUM
rather than INTEGER as the type of the displaced array, because a Lisp
Machine will signal an error if you try to store a bignum, or any
non-immediate data type, into an array displaced to a character array.

I believe Fortran 77 also disallows equivalencing character arrays with
other data types.

>> Yes, it's quite possible to write such code.  I'll bet pty is loaded with
>> system-dependency #ifdef's, though.  My guess is that the C world is
>> probably split about even between those two classes of programs.
>
>Nope, none at all in pty's case, except the common idiom #ifdef BSD
>#include <limits.h> #endif isolated in one include file. Everything else
>is a configuration option to select among available libraries. I think
>this is rather typical of both systems code and non-systems code in C.

When you say "select among available libraries", are you implying that all
the libraries are available in all the Unix implementations that pty runs
on, and it's the choice of the user running the configuration script which
one to use?  Or did you mean "select among possibly available libraries"?
If the latter, I thought that was the kind of dependencies that were being
described; whether the choice is made by a configuration script or #ifdef
directives seems like an insignificant detail.

Don't different Unix flavors have different naming schemes for pseudotty
devices?  I don't think SunOS has any libraries that deal specifically with
pseudotty's; every SunOS program I've ever seen that uses them contains an
inlined loop to find an available pty, open it, fork, etc.  It's really a
shame, because they each have different assumptions about the maximum
number of possible ptys, and frequently have to be updated when we increase
the number of ptys.

>  [ comments about whether Emacs is written in elisp or in C ]
>
>I see your point, but, as I've said before: I refuse to admit that you
>can change any fundamental characteristics of a language simply by
>adding a library. Sure, the GNU Emacs distribution comes with a lot of
>elisp code, without which you'd be insane to use the system. But that
>elisp code is on *top* of the Emacs program. Emacs is written in C, and
>no amount of library writing can change this fact.

I just remembered another difference.  The Emacs that end-users run is
created by starting up a bootstrap program that is written in C and
contains the Elisp interpreter and the C portions of the editor, loading in
Lisp libraries, and dumping the memory image out into an executable file.

By your reasoning, a program that I implement by loading code into Lucid
Lisp and dumping out the image is written in the language that Lucid Lisp
is written in, even though I might not even know how to program in that
language!
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

peter@ficc.ferranti.com (Peter da Silva) (03/29/91)

Look, folks, this C versus the world debate is the biggest pain in the
neck in comp.lang.misc. I apologise for my own small part in it, here,
and I'm bowing out. Next time you see someone claim that C can do
anything, or that C is bogus because it can't do something, keep this
in mind:

	Use the right tool for the job: C is the right tool for
	some jobs, because of the basic "portable assembler"
	design of the language lets you get down and dirty and
	write lean code. It is he wrong tool for some jobs, because
	the "portable assembler" design of the language forces
	you to get down and dirty and re-invent the wheel.

	The same is true of any language. You can write Fortran,
	Lisp, or Prolog style code in any language. If you're using
	a language that encourages lisp-style coding and what you
	need is a Forth, or you want to do AI and all you have is 
	Basic, you're going to do a lot more work or buy more hardware
	than if you pick the right tool.

AND: There has never been a language in which it is the least bit difficult
to write bad code...
-- 
Peter da Silva.  `-_-'  peter@ferranti.com
+1 713 274 5180.  'U`  "Have you hugged your wolf today?"

wilson@uicbert.eecs.uic.edu (Paul Wilson) (03/30/91)

peter@ficc.ferranti.com (Peter da Silva) writes:

>In article <1991Mar26.172536.12178@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
>>   A ``REAL source level debugger'' and incremental compilation are
>>   functions of the environment.

>Just for the hell of it, let me point out that the two languages that
>have the greatest number of units out with these features *are* statically
>typed: Forth and Basic.
        ^^^^^

But Forth doesn't have a "REAL source level," so how could it have a
REAL source level debugger? 

Anything where you see raw words on the stack (as opposed to variables
with names and/or types) sounds like debugging intermediate code to me.
:-)  (Sorry, I couldn't resist.)

>-- 
>Peter da Silva.  `-_-'  peter@ferranti.com
>+1 713 274 5180.  'U`  "Have you hugged your wolf today?"


    -- Paul

Paul R. Wilson                         
Software Systems Laboratory               lab ph.: (312) 996-9216
U. of Illin. at C. EECS Dept. (M/C 154)   wilson@bert.eecs.uic.edu
Box 4348   Chicago,IL 60680 
-- 
Paul R. Wilson                         
Software Systems Laboratory               lab ph.: (312) 996-9216
U. of Illin. at C. EECS Dept. (M/C 154)   wilson@bert.eecs.uic.edu
Box 4348   Chicago,IL 60680 

peter@ficc.ferranti.com (Peter da Silva) (03/30/91)

In article <1991Mar29.164740.25066@uicbert.eecs.uic.edu> wilson@uicbert.eecs.uic.edu (Paul Wilson) writes:
> peter@ficc.ferranti.com (Peter da Silva) writes:
> >In article <1991Mar26.172536.12178@linus.mitre.org> john@mingus.mitre.org (John D. Burger) writes:
> >>   A ``REAL source level debugger'' and incremental compilation are
> >>   functions of the environment.

> >Just for the hell of it, let me point out that the two languages that
> >have the greatest number of units out with these features *are* statically
> >typed: Forth and Basic.
>         ^^^^^

> But Forth doesn't have a "REAL source level," so how could it have a
> REAL source level debugger? 

> Anything where you see raw words on the stack (as opposed to variables
> with names and/or types) sounds like debugging intermediate code to me.
> :-)  (Sorry, I couldn't resist.)

This is a reasonable point, but I understand that people find other
stack-based languages (POP?, Postscript) quite adequate. For programming
in Forth, you have to think Forth:

	A-REASONABLE-POINT SWAP SET-ATTRIBUTE
	LANGUAGES STACK-BASED DUP POP ?HAS-ATTRIBUTE 0= ABORT" OOPS"
		DUP POSTSCRIPT HAS-ATTRIBUTE
		OTHER-PEOPLE FIND-REASONABLE SELF UNDERSTANDING SET-ATTRIBUTE
	FORTH PROGRAMMING-IN IF FORTH THINK THEN

Oops, I left stack-based languages on the stack.
-- 
Peter da Silva.  `-_-'  peter@ferranti.com
+1 713 274 5180.  'U`  "Have you hugged your wolf today?"

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (04/01/91)

In article <1991Mar29.064102.24914@Think.COM> barmar@think.com (Barry Margolin) writes:
> 	char buf[sizeof int];
> 	*(int *)&buf = 1;
> what is the value of buf[0]?  On some machines it will be 0, on other
> machines it will be 1, and some strange machines could produce other
> values.

So what? Just because code is portable doesn't mean it will produce the
same results on different machines. What's 32767 * 32767 in Ada?

The code works, is useful, and has well-defined results under any C
compiler. It can't be translated into portable Lisp code.

> Or did you mean "select among possibly available libraries"?

Yep, that one. It is not a failure of C that different C platforms
provide different nonstandard libraries, and an application that can
take advantage of such libraries is hardly ``loaded with
machine-dependent #ifdefs.''

> Don't different Unix flavors have different naming schemes for pseudotty
> devices?  I don't think SunOS has any libraries that deal specifically with
> pseudotty's; every SunOS program I've ever seen that uses them contains an
> inlined loop to find an available pty, open it, fork, etc.  It's really a
> shame, because they each have different assumptions about the maximum
> number of possible ptys, and frequently have to be updated when we increase
> the number of ptys.

Yes, it is, and wouldn't it be a lot simpler if all these assumptions
were isolated in a couple of configuration options in a single program?

> By your reasoning, a program that I implement by loading code into Lucid
> Lisp and dumping out the image is written in the language that Lucid Lisp
> is written in, even though I might not even know how to program in that
> language!

No. I didn't say elisp code was written in C. I said Emacs was written
in C. Just because it happens to come with a whole bunch of elisp
add-ons doesn't change the language Emacs is written in.

Would you say C is written in C, just because C platforms come with a
whole bunch of libraries that C programs can use?

---Dan