Hacker News new | ask | show | jobs
by tqs 5138 days ago
Gutenberg didn't invent a machine for quickly producing books, he invented a machine for quickly producing machines for quickly producing books!

That is, his key innovation was a way to mass-produce the characters (the movable type) which could then be arranged to mass-produce the printed pages.

First, individual characters were carved from steel (each taking about a day to make). This was the only part of the process done "by hand". Every other element of the process was produced through some form of (repeatable/arrangeable) transfer of shape/information.

The master characters were hammered into brass to create a mold which could then be reused to cast multiple copies of a character. Each page had thousands of characters and Gutenberg's shop had multiple presses going at a time, so they needed lots of these characters on hand (50,000 is a conservative estimate).

The masters could also be easily transported to another city. These masters (plus raw materials of course) were all that was needed to set up a new print shop. This enabled the printing press technology to quickly spread throughout Europe.

I think it's a good analogy for the power of software :)

Source: http://retinart.net/beautiful-things/gutenberg-book-changed-...

1 comments

Yeah, that’s a good parallel. Copying is cheap and automation is applied not only to a task, but to the automation of the task.
this 2 fold demultiplication hits my mind regularly.

  instance / class / metaclass / ()
  instance / model / metamodel / ()   -- very redundant.
  value    / type  / kind      / ()
  machine  / vm    / utm       / ()
() denotes the closed loop where you don't need another layer.

anybody has a theory that explains this trait ?

It’s just a linguistic phenomenon. In English, at least, the prefix meta- denotes not only a single level of metaness (if you will) but also two levels or more, e.g., meta-metaclassmetaclass. So the “closed loop” is there only for convenience, like saying “and so on”.

If we were being precise, we would explicitly denote the level at which we were working. However, we tend not to do so for two reasons: first, that we rarely work with n-meta things for high n; and second, that being explicit is just plain unwieldy.

It’s for the same reason that we follow line, square, and cube with 4-cube, 5-cube, &c.

i think it's deeper than that. the progression is from object (every one hand-crafted) to template-based object-maker (hand-crafted per kind of object, but can produce a bunch of objects of that kind), to metatemplate-based template maker.

however, once you hit that second level of abstraction, you have almost invariably added enough flexibility that the range of templates your template-maker can make includes templates for other template makers. that is, it's not just a quirk of linguistics that a meta-meta-template-maker is called a meta-template-maker, they really do tend to be objects on the same level of abstraction and flexibility.

We seem to be saying the same thing; I just don’t see any inherent meaning in it. A literal interpretation of meta- would have us define it like this:

    Instance ::= 0
    Meta(X)  ::= Succ(X)
But it’s much more convenient to define meta- recursively:

    Instance ::= 0
    Meta(X)  ::= Succ(X)
               | Meta(Succ(X))
In both cases, we have an arbitrary designation:

    Class    ::= Succ(Instance)
That kind of redundancy is a linguistic artifact, not a deeply meaningful one.

It’s not the case that reaching the second level of abstraction necessarily results in enough flexibility to make the inductive step. As a counterexample, consider C macros, which only add one meta- because they are only expanded once. Lisp macros, on the other hand, are expanded until a fixed point is found. That’s why Lisp macros are Turing-complete while the C preprocessor is only a pushdown automaton.

A bit of disagreement with your last paragraph: The (Common) Lisp macro processor is Turing-complete trivially because it invokes a Turing-complete language along the way, not because of power inherent in its expansion strategy.

Common Lisp macro bodies are written in Common Lisp, i.e. written in a Turing-complete language — they would still be Turing-complete even if we wrote them in the subset Lisp-without-macros. The C preprocessor, on the other hand, does not invoke a Turing-complete language to compute a macro's expansion.

Of course.. zero, one, infinity strikes again.