Re: Scripts vs APIs

Linas Vepstas (linas@innerdoor.austin.ibm.com)
Thu, 8 Sep 1994 21:56:30 -0500


Hi John,

> From: ellson@hotsand.att.com (John Ellson)
> To: linas@innerdoor.austin.ibm.com, mddoyle@netcom.com, unitcirc@netcom.com
> Cc: www-vrml@wired.com
> Date: Thu, 8 Sep 94 20:43:35 EDT
>
> > I want to draw a distinction between a "variable" and a "named object"
> > (aka "alias" aka "proxy" aka "surrogate"). Thus, I can declare
> >
> > bigGreenKnob { polygon { vertex ... vertex ... }}
> >
> > and use bigGreenThing as a handle refering to a large, complicated object.
> > If the language allows bigGreenThing to be redefined at a later time
> > to be something else, then bigGreenThing is a "variable". If it is
> > illegal to redefine bigGreenThing, then it is merely a name. The former
> > is the hallmark of a proceedural language, the later is that of a
> > declarative language. Again, the later is usually easier to handle.
>
> OK. I see there is a middle ground. I'm not a language expert so
> I must admit that I find the distinction between a variable and a once-named
> object a bit subtle, but I can see the possibilities.

Think of the differences from the implementors side:
memory management -- a named object, once declared, is known to be
pointing at a valid group of data of a known size. That's that.

Assigning to a variable may require some previous object to be deleted
and freed, (since there are no references to it) -- thus you need a
garbage collection scheme, and a reference/use-count scheme. Yech.
You may have to malloc or realloc memory of a different size as the
variable is assigned to. Fragmentation. Yech.

When you go to use a variable ... is it pointing to something valid?
If it is, is that value up-to-date? With a "name", I can pre-digest,
precompute stuff when the named object is defined. For example,
for a 3D geometric named object, I can build an OpenGL display list,
which is in some compact, binary, internal format. But with a variable,
I have to ask ... is the display list I'm holding on to valid, or has
it changed? If so, then rebuild the display list (a performance hit).

Generically, this implies that caching is easy for named objects,
hard for variables, since (1) you need a cache invalidation scheme,
(2) you need to rebuild caches at possibly inconvenient times.
Thus, interpreters usually punt on caching. With a compiler
you can spend some time digesting things, figuring out whats going
on, and globablly optimize so that you don't thrash around
building & rebuilding display lists (for a C language analogue
-- fetching & re-fecthing from memory, vs. keeping the most heavily
used variables in registers). Thus, for performance reasons,
proceedural languages eventually get compilers ...

> I guess that depends on the application. One application that I have in mind
> is to photorealistically render pieces of electronic equipment in a
> telephone network so that it can be visualized and managed remotely. Many of
> the structures that I want to render are regular, e.g 20 ICs on a
> board, 20 boards in a shelf, 4 shelves in a bay, 10 bays in an
> equipment-aisle, .....
>
> Can a declarative language provide an equivalent to a translate-and-copy-n-times
> iterator?

Why of course! Notice that your english-language description was
a description, not a proceedure! Thus, I can rip off your english
language to create some pseudo-VRML:

DefineObject pcboard { // pcboard is the name ...
Iterator { // an iterator that applies a transform, and copies ...
Translate {0.0, 1.21, 0.0}, // the transform to apply at each step ...
knobbyBlackThing // geometry for an IC chip I'd previously defined
20 // make 20 copies ...
}
}

When the VRML interpreter hits this, it does it trivially, just
as if Iterator was on par with a Sphere ...

DefineObject pcboard { // pcboard is the name ...
Sphere { // a sphere object
Translate {0.0, 1.21, 0.0}, // the center of the sphere
knobbyBlackThing // a cool looking texture map
20 // with a radius of 20
}
}

Compare that to

DefineObject pcboard { // pcboard is the name ...
for i=1, 20 { // interpreter allocates memory for i, stores value for i
Translate {0.0, 1.21, 0.0}, // interpreter malloc memory for transform,
// copies value into memory
Instance knobbyBlackThing, // malloc memory for object, copy pointer
// to knobby black thing into that memory
} // increment i; if done, free memory for i
}

which would result in 41 memory allocations, 20 constructions of a matrix
object, 20 copies of an identical matrix object (what a waste of memory ...
but how was the interpreter to know? Maybe the next line of the program
would change the matrix object ... but since we don't have a compiler,
we don't know what the next line of the program does. So we play
it safe and assume that somewhere further on in the loop, somebody
fiddled with the matrix, and so we make a copy.) ... etc.

--- phew ---
One could also use recusrion, and terminate the recusrion after 20 times.
Recursion has the merit of being useful for generating fractals ...

-------
> I fear that I beginning to show my bias, but in tcl everything is a
> string, so typing is not a problem. (Unless you feel that the
> language should be strongly typed?)

Hmmm ... what happens when someone hands you a sphere, and then
says, "no, its a cube". Typing has its place ...

---linas