Having trouble making a simple recursive inspector.

Bay-Wei Chang bay at amuck
Mon Oct 15 20:00:59 UTC 1990

Methods don't respond to _MirrorReflectee because returning an object with
code evaluates that code.  This is almost definitely not what you want when
you are examining objects via mirrors on them; in fact, one reason mirrors
exist is to allow examination of a method object without evaluating it.

Your code:

> _AddSlots: (| irec: = (| :obj m. | m: obj _Mirror. inspect: obj.
>	m _MirrorSize do:
>		[|:n| irec: (m _MirrorContentsAt: n) _MirrorReflectee].)|)

[Aside: the :obj requires a '.' separating it from the slot declaration m.
Also, it is common practice to place the arguments interspersed with the
keywords of the slot name, ie,

  irec: obj = ( | m | ... )

though declaring :obj with the other local slots is also correct.]

If _MirrorReflectee did return the method object, it would be evaluated, and
the argument to irec: would be the result of that evaluation rather than the
method object.

In the code above, _MirrorContentsAt: returns a mirror, and _MirrorReflectee
returns the object; then irec: goes and gets the mirror again with _Mirror.
Instead, stay with the mirror:

  _AddSlots: ( |
      ^ irec: obj = ( irecReflectee: obj _Mirror ).

      _ irecReflectee: aMirror = (
          inspectReflectee: aMirror.
	  aMirror _MirrorSize do: [ | :n |
	      irecReflectee: aMirror _MirrorContentsAt: n ]. ).
  | )

inspectReflectee: is a private slot (defined in inspect.self) that takes
a mirror and prints the slots of its reflectee; inspect: calls this method.

Finally, it is common practice to avoid using primitives directly, except
when absolutely necessary.  This insulates code from low-level changes in
primitives, allows any necessary housekeeping to be done in the Self wrapper
methods, as well as permits lookups to be performed rather than primitives
being executed directly.  For example, sending the message 'reflectee' to
a mirror on a method results in a Self-level error stating that methods
may not be accessed through their mirrors; sending the primitive
_MirrorReflectee results in the virtual machine giving a reflectTypeError.
Thus the code above (without any direct primitive invocations) would be:

  _AddSlots: ( |
      ^ irec: obj = ( irecReflectee:  reflect: obj ).

      _ irecReflectee: aMirror = (
          inspectReflectee: aMirror.
	  aMirror size do: [ | :n |
	      irecReflectee: aMirror contentsAt: n ]. ).
  | )

It's great that you're writing Self code!  Feel free to post other questions.


More information about the Self-interest mailing list