Subject: Re: garnet performance issues
From: Erik Naggum <erik@naggum.no>
Date: 1999/02/14
Newsgroups: comp.lang.lisp
Message-ID: <3127945291589453@naggum.no>

* Erik Naggum <erik@naggum.no> writes:
| the whole parameterized type nonsense is a testament to bad language
| design.  it is completely devoid of meaning.

* Juliusz Chroboczek <jec@dcs.ed.ac.uk>
| I beg to disagree.

  um, what part of it do you disagree with?

  in case it hasn't been clear, I have been trying to show that Common Lisp
  _has_ what C++ calls parameterized types, and has had it since way before
  C++ was conceived.  the overall context here is "why reject Common Lisp?"
  and one argument was: "it doesn't have parameterized types", where
  "parameterized type" is a language-specific feature in C++, much hyped
  because the language lacks everything that would make this a _natural_
  thing in C++.  the whole idea of adding parameterized types to a language
  that doesn't have a useful way of representing type information at
  run-time is just silly.

  so, I'm not arguing against _types_.  criminy.  I'm not arguing against
  the ability to reason about code.  how could I be a strong favor of type
  inference and author of code analysis tools if I were?  I'm not arguing
  about the usefulness of type calculus.  geez, my University education was
  all about static typing and verification and all that stuff that has yet
  to prove itself because it's just too hard on programmers to tell these
  things all they need to know.

  I'm arguing against the stupid disdain for dynamic typing and run-time
  type information (in C++ terms) except as an inefficient last resort when
  it's too hard to do it statically.

| Whether type declarations are compulsory in the code, optional, or not
| written at all, and whether they are statically or dynamically checked
| is more or less irrelevant to this discussion.

  I think they are irrelevant only to your own discussion, which doesn't
  address anything people here have actually argued against.  my argument
  is that you cannot both wish to retain type information _and_ drop it.
  if your language can't speak about its types, any benefit of this type
  business is in efficiency in the compiler.  if you want to reason about
  types, you just can't do it in C++, and it is entirely irrelevant to any
  abstract meaning of "parameterized type" -- C++ does not instantiate it
  in a useful way, while Common Lisp does.

| In this view, being able to express notions such as `list of integers' is
| a perfectly natural request.

  there is a point at which you have to ask of any theory what it will
  change for the better if people adopted it.  theories that are very nice
  and clean and powerful which change nothing in the ways people think or
  act in practice are ineffectual in the extreme.  I want theories that are
  so powerful that people change their ways _completely_, because what
  people do today is mostly stupid, especially in the language design area.

  do we have the concept of a "list of integers" in Common Lisp?  yes.  is
  it different from any other list, operationally and notationally?  no.
  did C++ have the concept of a "list of integers"?  _no_.  it then chose
  to add a list implementation that _had_ to be specialized on the type.
  of course, this is a pain.  so naturally the non-solution "parameterized
  types" had to be invented.  this is not because of any lack of usefulness
  of typeful languages, not because people do not want "list of integers",
  but because C++ has no concept of a _type_hierarchy_ that would allow
  "list of any-type" to be expressed usefully.  all C++ can do is "list of
  some-type", and since its types do not form a hierarchy, but are disjoint
  (even the classes, there is no "universal superclass") so instantiation
  of the type becomes a _necessity_.  the concept of "parameterized types"
  were born out of this necessity.

  now, in a type calculus, you don't talk about types as any special kind
  of parameter, it's your _favorite_ kind of parameter.  you compute types
  and of course it takes types as arguments.  making up "parameterized
  type" as a phrase means you _don't_ usually compute or specify types
  abstractly.  in other words, you need the terminology because it is
  something people need to be aware that they can do, and there is no space
  for it in their existing vocabulary.

| A number of people ... are even working on calculi in which you have the
| full power of the lambda-calculus at the level of types -- very natural
| if you've been brought up on Lisp, and like to have full access to the
| language at compile-time.

  well, here's my biggest gripe with the explicit-typing crowd: they have a
  notion of a dichotomy between run-time and compile-time, and it's a moral
  dichotomy: "what's good at compile-time is bad at runtime, and what's
  good at run-time is bad at compile-time".  macros in Lisp aren't
  different from any other function, they are just called under slightly
  different conditions.  the _same_ language is used.  why did they need a
  _new_ language to get a lambda-calculus for typs?  well, I think it's
  because the language in question is so badly designed that they had to.

  in all the literature I have read about types, and it's considerable,
  this notion is hidden under a lot of consequences of holding it, but
  never made explicit.  I think the reason it is not explicit is that it is
  genuinely stupid, and like so many other things in our cultures and
  traditions that are stupid, smart people find smart ways around them, and
  it's fundamentally risky to stand up and say "this is stupid" without
  having a much better idea, because millions of people will flock to the
  defense of the stpuid old traditions without even considering the other
  idea unless it's so intuitively superior that people go "ah, of course",
  instead.  so real progress happens only when some genius is willing to
  ignore the stupid ways and do something that opens up entirely new paths.
  in this case, inventing parameterized types hss done nothing to help us
  get out of the stupid ways.  if people were somewhat less insistent on
  obeying the stupid ways of their ancestors, maybe we also could have more
  respect for their _smart_ ways.  but I digress.  (and don't get me
  started on foreign aid to countries where a family's prestige is
  determined by how many male children they have.)

| You may then express types such as `vector of int of length 42'

  (vector integer 42)

| or `cons is for any n:int a function from vectors of length n to vectors
| of length n+1'.  (I don't think the latter can be expressed in Common
| Lisp, not even with SATISFIES.)

  I assume some function like ADJUST-ARRAY was intended, not CONS, since
  CONS doesn't do that and it's good that it cannot be expressed in Common
  Lisp.  (why do people who want to make theoretical points so often miss
  the details in ways that shows that they have genuine disdain for them?)

  recently, an implementation of core concepts in programming by contract
  was posted here, in Common Lisp.  you can certainly express the above in
  such a system.  (I know the argument to follow: "but does it help the
  compiler produce better code?" -- more on that just below.)

| (No, those calculi are not ready for general consumption by programmers,
| although they've been remarkably successful in theorem proving.)

  I think you underestimate practitioners, but hey, that's the norm when
  people invent theories that have _zero_ effect on the way they work.

  here's my view on this type business: it makes no difference whatsoever
  whether you compute types at run-time or at compile-time, you can reason
  about the code just the same.  (people who scream and shout that they
  can't, have yet to discover the simple concept of a type hierarchy with
  embracive, abstract types like NUMBER instead of "integer of 16 bits"
  being disjoint from "integer of 32 bits")  it makes no difference to
  anything except performance whether the system has to figure out the type
  of an object at run-time or at compile-time, and since we have a type
  hierarchy for everything, the way to move something into the compile-time
  arena is either by type inference or hints from the programmer.  and if
  the programmer wants to ensure that he does not see type mismatches, he
  can either write code for it or declarations for it, which are identical
  in conceptual terms.  (in particular, if you check for a type, you know
  that whatever was checked has that type afterwards, just like you would
  if you had a declaration -- so why do the strong-typing crowd get so anal
  about this?)

  despite all the hype and noise about parameterized types in C++, you
  still can't use it any useful way at run-time.  all you can hope for is
  that the compiler did all the useful things by the time the code was cast
  in stone, and hopefully didn't make any mistakes (which the C++ template
  cruft has been suffering from in all implementations for years).  in my
  view, this restriction on type calculus is phenomenally stupid, and
  anyone who works with strong typing after accepting the dichotomy between
  run-time and compile-time is unlikely to contribute anything of serious
  value, simply because the mind-set is too narrow.  in particular, if it
  is necessary to study how something behaves in a run-time situation in
  order to come up with a breakthrough idea, the person who believes in
  compile-time will have to invent his own _language_ and write a compiler
  for it, which is just so much work that no sane person would want to do
  it just to prove a simple point, and if someone did it anyway, you would
  get a new language with a number of features that couldn't be used
  anywhere else, and nothing would come of it until C++ incorporated a
  braindamaged version of it so people could argue against Common Lisp not
  adopting "modern trends in object-orientedness" or whatever their
  argument was.

  in brief, the strong typing community are solving the wrong problems the
  wrong ways.  the results of their work increasingly depend on accepting
  that certain operations are _bad_ at run-time, and they provide the world
  with their results in the shape of immature, specialized languages that
  cater to their own aesthetics and very few other people's actual needs.

  strong-typing language researchers prove their points with languages.
  Lisp programmers and theoricians alike prove them with macros.

  so, to repeat myself: I'm not arguing against type theories, not arguing
  against the usefulness of various forms of type inference, not arguing
  against reasonable requests, not arguing against the desire to reason
  about code, not arguing against tools to ensure correctness and all that
  good stuf.  I am arguing against the belief that types belong in the
  compiler and not in the running system, and I am arguing that the
  specific idea of a "parameterized type" is moot in Common Lisp, both
  because we have typed objects and because we have a type hierarchy for
  _all_ types with specialization on disjoint types.  I am arguing that
  parameterized types are _necessary_ when you accept disjoint types and
  believe in the compiler as your only savior.

  I hope this avoids any more arguments as if I was deriding or did not
  understand type theory.  I have a specific gripe with one of its core
  premises, not the random, unlearned hostility to theories as such that
  theoreticians who have a random, unexperienced hostility to practice so
  frequently believe their critics suffer from.

#:Erik