[OT] Strong/Weak/Dynamic/Static typing (was Re: Python Strings)

Jonadab the Unsightly One jonadab at bright.net
Fri Sep 22 11:41:44 EDT 2000


m.faassen at vet.uu.nl (Martijn Faassen) wrote:

> > Actually, this discussion has me trying to classify Inform's
> > typing system, and I'm having trouble.  Perhaps if I describe
> > its typing system you can tell me how to classify it...
> 
> Trying to figure it out now..
>
> > Everything is an integer.  I'll explain.  If you assign an
> > integer to a variable, that integer is literally stored in
> > the variable itself -- so the variable actually holds the
> > integer.
> 
> All right. So, in Pythonic syntax:
> 
> a = 1
> 
> Should behave similar to Python, though the implementation in Inform
> seems different as no integer object is created.

Right.  There's no integer object; the variable just literally
holds the integer.  This happens whether the variable is a 
declared global, a local belonging to a routine, or a property 
of an object.  

> >  If you assign anything *else* to a variable,
> > the item itself is not stored.  An integer is stored.  For
> > some kinds of things (strings, routines) the stored value
> > is a packed address.
> 
> Okay, so in that case, variables are references to these objects.

Yes, essentially (although Inform parlance normally reserves
the term "object" for an object specifically, but I understand
what you mean).  However, variables don't hold references
to objects in exactly the same way; notably, they do not hold
the address.  (It is in theory possible to get the address of 
an object from the object table using zasm instructions[6], 
but you would not normally every have any reason to do that.)
The difference here is often transparent to the programmer,
but not *quite* always.  Since objects are numbered sequentially,
and since you normally include the parser at the top of your
code before defining any objects, and since the last object
the parser defines is selfobj, the cannonical way to loop
through all of your own objects is like this:
  for (i=selfobj+1:i<=top_object:i++) { 
     ! Do stuff
  }
(top_object is a constant the compiler defines for you, 
IIRC.)  So you see that there are *occasions* when it
is exposed that these references to objects are actually
integers.  Usually you don't think about it, but it
crops up from time to time.  (The packed addresses of
routines and strings almost *never* crop up, however.)

> How does Inform know whether a variable contains an 
> integer or an address? 

It doesn't.  However, if the variable contains a packed
address, you can (via a very odd and contrived library
routine called ZRegion -- the language author wanted to
make it more straightforward but couldn't really given 
the limitations of the VM to which Inform compiles,
which he didn't create[2]) determine whether it refers 
to a string or a routine or something else.  (The only 
something else it normally would be is an object number.  
If it were, for example, a property or dictionary word, 
you who wrote the code would *know* that you made such 
an assignment.)  Furthermore, if the integer in question
is an object number (for example), it's guaranteed by
the structure of the VM to be less than the smallest
packed address[7], so it could never be confused with
a string or routine.  

> Does the variable name have a type associated too, or
> is some other magic going on?

That which cannot be determined by ZRegion[8], the 
programmer is responsible to know.  In practice, this is 
seldom a problem, because generally the only three things 
you assign in an interchangeable manner are strings, 
routines, and objects.  Anything else, while the variable 
does not hold a specific type as far as the language is 
concerned, in practice would be assigned to a variable 
that the programmer knows contains that kind of thing.

> > For other kinds of things (attributes,
> > properties, dictionary words, objects, classes, ...) the 
> > value stored is a unique ordinal number.  (So, the first
> > dictionary word that appears in the code will be 1, and
> > so on.  The first property declared will also be 1.  And
> > the first object.  Et cetera.)
> 
> I'm not sure I understand this. Does this mean you have addresses here
> as well, but in a fixed range (or array indices, if you like).

Indices is closer.  If you have 879 objects in your code,
they will be numbered 1 to 879.  This is part of the
structure of the VM, the z-machine, which has an object
table hardwired IIUC.  Similar for attributes, properties,
and dictionary words.  (I'm stone cold certain the VM
has the dictionary hardwired, since if you use zasm (the
assembly language for this VM) there are instructions
for tokenising.)

> > So, if you have an object...
> 
> > Object foo "foo";
> 
> What's the "foo" bit about?

That's the object's hardware short name.  It is required
unless you include a short_name property and is a good
idea anyway.  Without delving too much into the way
Inform handles user I/O (which puts many other languages
to shame in a number of ways, but nevermind), the program 
will call the object a foo when it talks to the user.
The non-quoted foo is the internal name, which the
program code uses to refer to the object.  If the user
needs to be able to refer to the object, then you use
either a name property or, if you need to do more
complicated stuff, a parse_name routine.

> > And you give the object some attributes...
> 
> > give foo openable open container;
> 
> > You can copy those attributes to another object...
> 
> > for (i=1:i<=last_attribute:i++) 
> >    if (foo has i) give bar i; 
> >       else give bar ~i;
> 
> What does the 'give bar ~i' part do?

It clears the i attribute of bar.  The ~ reads as "not".
Attributes, I should clarify, are strictly boolean.
(They are literally stored as one bit per attribute
per object in the compiled binary.)  This is really
the only static typing in Inform.  Properties, globals,
and locals can hold anything, as discussed, but attributes 
are just either set or not.  Again, this is hardwired
into the VM, which was created LONG before the language.
(This is where Inform gets its portability[3].)

> > It's very different from the type system of, 
> > say, Perl...  maybe it's yet some other kind
> > of typing?  Or are "weak typing" and "dynamic
> > typing" sufficiently general terms to include
> > this system?
> 
> I think that is Perl's type system is similar to Python's you could
> pull off some of this copying as well.

My point is not that you can copy attributes.  I realise both
Perl and Python are far more powerful than Inform (unless you
happen to be doing natural language processing...)  I was 
pointing out the manner in which it can be done, which
says something about the kind of typing -- I'm just not
sure what.

> What Inform seems to do is expose some implementation details (addresses),
> though I'm not quite sure how it could work internally yet..

Actually, they're not really exposed to the casual programmer;
the Designer's Manual doesn't talk about them really.  I know 
about them because I've read the technical manual and the 
specification of the z-machine and no small number of related
technical discussions on rec.arts.int-fiction.  As far as the
casual programmer is aware, you can simply do something like
the code below.  Notice that the description property of one
object holds a string, and the description property of the 
very next object holds a routine (which executes a rather
lousy joke I shamelessly ripped off from Graham Nelson for
the sake of the example, but nevermind).  When the library
is ready to print the description of the first object, it
discovers a string and just prints it.  When it is ready
to print a description of the second object, it discovers
a routine and runs it.  Since the routine returns true[1] 
rather than false (which would be the default) it assumes 
that the routine has printed something.  If the routine
had not returned true, the library would have printed
a default "You see nothing special about the spade."
There are similar cases where you can substitute a 
routine for an object.  And there are library routines
in case the programmer needs to do this kind of thing 
himself.  Calling PrintOrRun on an object property will
print it if it's a string and run it if it's a routine,
returning the return value of the routine (or true if 
it was a string).  ValueOrRun similarly will run
it if it's a routine (and return its return value)
or otherwise will simply return its value if it is
not a routine.  Here's an example of substituting
a routine for a string...

Object lawnmower "lawn mower" garage
  with name 'lawn' 'mower' 'lawnboy' 'green',
       description "It's a green lawnboy.  This isn't an example
                    of exemplary writing, but I'm demonstrating
                    a point.",
       ! ... insert more stuff here...
  has  switchable;

Object spade "implement" garage
  with name 'spade' 'shovel' 'garden' 'implement',
       description [;
             if (self.short_name == "garden implement")
             {   
                 self.short_name = "spade";
                 "On second thought, let's just call a 
                  spade a spade.";
             }
             "It looks like any other spade you've ever seen.";
         ],
       ! ... insert more of the shovel's code here...
       short_name "garden implement";

And here's an example of substituting a routine for an object...

Room kitchen "KITCHEN"
  with description "Some lavish description of 
                    the kitchen goes here.",
       s_to diningroom,
       ! More properties here...
  has  light;

Room diningroom "DININGROOM"
  with description "Some lavish description of 
                    the dining room goes here.",
       n_to kitchen,
       s_to [;
          if (livingroom has general) 
          {
             "There's nothing but a heap of rubble 
              in that direction.";
             ! Presumably we would have explained 
             ! why when we set the general attribute,
             ! but perhaps that code is contained in
             ! the livingroom object itself, which
             ! handily allows me to evade explaining 
             ! it here..
          }
          return livingroom;
          ],
  has  light;

[1] By way of implicit print_ret; see the Inform Designer's 
    Manual or just take my word for it.

[2] The z-machine was created by Infocom, originally
    for Zork.  These days most z-machine emulators
    (which we usually call interpreters) are by some
    third-party or another, but at the time Infocom
    ported one to every platform for which they 
    released any of their games, so when GN created 
    Inform to compile to this VM, there was already
    wide portability; there is much better portability
    for the z-machine now than there was then.

[3] MUCH more portability[4] than Python, but of 
    course it has a cost in power.  There is no 
    dynamic memory allocation; there is no real file 
    I/O... OTOH, Inform is sufficiently powerful that 
    there have been a least three interpreters written 
    in it (one for Befunge, one for a subset of Lisp, 
    and one for a subset of Scheme).  It's PLENTY
    powerful for its intended purpose of creating
    text-based interactive games.  There is also
    now a newer VM (glulx) which kicks out all the
    size limitations a few orders of magnitude
    and supports sound and graphics and I think 
    limited file I/O; it will still be more portable 
    and less powerful than Perl or Python.

[4] z-code can be run on the old rusty mainframes 
    and 8-bit micros from the seventies[5], the 
    palmtops of the nineties, the PDP11, Nintendo 
    Gameboy, Emacs, and certain brands of handheld 
    calculators, among other things.  The only 
    platform I know about that does not have a 
    z-machine is the AS/400.  Of course, major 
    platforms like DOS have a choice of dozens of 
    z-machines, all mutually interchangeable 
    (although some offer nice features (like 
    command-line editing, a choice of colours and 
    fonts, and multiple levels of undo) that are 
    simply not possible on some of the minor 
    platforms).

[5] Kaypro, TRS80, Commodore, ... things that
    make the Apple //c look like the state of
    the art.  

[6] zasm as in "z assembler", which the Inform
    compiler understands, but it's not considered
    part of the Inform language, and the casual
    programmer need never use these instructions.
    Also, they're meaningless if you're compiling
    to glulx instead of the z-machine.

[7] The low addresses (which are not packed) are 
    RAM, and the packed addresses are ROM.
    So all strings and routines are in ROM, but 
    all objects reside in RAM.  Since an object 
    takes up a number of bytes minimally, there can 
    never be nearly as many objects as the amount 
    of RAM, and thus there can never be an object 
    with a number as high as the lowest packed 
    address.  So ZRegion checks the integer that
    a given variable holds, and if it's lower
    than the lowest packed address it says "this
    is something else" (i.e., not a routine or 
    a string).  If you assigned an object, 
    ZRegion will never think it is a string or
    a routine.  Nor can it confuse strings and
    routines, because the compiler segregates 
    them in ROM and keeps track of the address
    ranges that can refer to each for ZRegion's
    benefit.  It's a kludge, but it works, and
    it lets the compiler, library, and indeed the
    program see distinctions that apparently the 
    VM was not designed to see.  There are also
    classes, which are an object as far as the
    VM is concerned; you can always tell whether 
    an object is a class or a real object (because 
    of some under-the-surface magic the compiler 
    puts into the property table for the object, 
    the details of which I don't really know)
    by checking metaclass(foo).

[8] or metaclass.

[9] I know these footnotes don't appear in order.
    I didn't write the post in order.  I usually
    don't write straight from beginning to end.
    Besides, there is no footnote 9.

- jonadab



More information about the Python-list mailing list