Subtleties of the CONTENT Tag

You have probably used them already: container macros and the <$content> tag. And perhaps you have also noticed, that in some examples I have used somewhat different constructions than what the documentation says you should. Yes, there's a reason apart from elitism ;-)

The problem

Basically, as the documentation says, you declare a macro with the /CLOSE modifier, and access the stuff you wrote between the start and end tag with <$content>. Like this:


<$macro SIMON-SAYS /CLOSE>
Simon says: <$content>
</$macro>

Obviously, this will prepend everything you enclose in these tags with "Simon says:". But that may be too unflexible for you. Let's say one of your customers likes the pages you do but doesn't like this bloke from the bible, he'd rather have Muhammad tell him what to do. So to avoid having to rewrite your pages, you define a new macro:


<$macro SIMON-SAYS /CLOSE>
  <$if COND=(defined SIMONSUCKS)>
    Muhammad says:
  <$else>
    Simon says:
  </$if>
  <$content>
</$macro>

Testing:


<SIMON-SAYS>use HSC!</SIMON-SAYS><BR>
<$define SIMONSUCKS:bool> <* type doesn't matter *>
<SIMON-SAYS>use HSC!</SIMON-SAYS>

Simon says: use HSC!
Muhammad says: use HSC!

They agree! :-)
Now what about using both versions in one document? If you have Simon on top, no problem. But once the variable is defined, Simon is gone until the end of the document. SIMONSUCKS indeed...
How about HSC's local variables? If you had another container macro, you could define SIMONSUCKS locally and it would disappear as soon as HSC sees this macro's end tag. Let's try it:


<$macro NOSIMON /CLOSE>
<$define SIMONSUCKS:bool>
<$content>
</$macro>

<NOSIMON>
<SIMON-SAYS>use HSC!</SIMON-SAYS>
</NOSIMON>
<SIMON-SAYS>use HSC!</SIMON-SAYS>

Simon says: use HSC!
Simon says: use HSC!

What's that? It says "Simon" twice, while the first time it should have said "Muhammad"—that's what we defined the <NOSIMON> macro for. Apparently, SIMONSUX is not defined in an enclosed container macro, so local variables can not be used!

The solution

Of course there is a solution, or this article would be fairly pointless. If you have read the loops tutorial, you probably guessed what to do:


<$macro NOSIMON /CLOSE>
<$define SIMONSUCKS:bool>
<(HSC.Content)> <*---Look-here--- *>
</$macro>

<NOSIMON>
<SIMON-SAYS>use HSC!</SIMON-SAYS>
</NOSIMON>
<SIMON-SAYS>use HSC!</SIMON-SAYS>

Muhammad says: use HSC!
Simon says: use HSC!

There you are!

Expansionism

Frankly I'm not sure whether Thomas thought of these implications when he designed HSC, because in his macros this mechanism is never used. However, it is the key to loads of programming tricks, including loops, semiautomatic layout and other weird things probably never meant to be in HSC =^>

The reason for the difference between <$content> and <(HSC.Content)> is the order of expansion:
<$content> is first expanded, then its result is inserted in the enclosing macro.
<(HSC.Content)> is first inserted verbatim, i.e. including all unexpanded macro calls, and is then expanded together with its container in the current context

Everybody confused? Fine. Took me a while to figure it out, too ;)
If you take the last example using <$content> and expand the macro calls "by hand", you get this:

  1. All unexpanded macros
    <$macro SIMON-SAYS /CLOSE>
      <$if COND=(defined SIMONSUCKS)>
        Muhammad says:
      <$else>
        Simon says:
      </$if>
      <$content>
    </$macro>
    
    <$macro NOSIMON /CLOSE>
    <$define SIMONSUCKS:bool>
    <$content>
    </$macro>
    
    <NOSIMON>
    <SIMON-SAYS>use HSC!</SIMON-SAYS>
    </NOSIMON>
  2. Inner macro SIMON-SAYS expanded
    <NOSIMON>
      Simon says: use HSC!
    </NOSIMON>
  3. All expanded
    <$define SIMONSUCKS:bool>
      Simon says: use HSC!

Obviously the variable definition doesn't have any effect on the already expanded macro call below it. Now take the other construction using <(HSC.Content)> and expand it:

  1. All unexpanded macros
    <$macro SIMON-SAYS /CLOSE>
      <$if COND=(defined SIMONSUCKS)>
        Muhammad says:
      <$else>
        Simon says:
      </$if>
      <$content>
    </$macro>
    
    <$macro NOSIMON /CLOSE>
    <$define SIMONSUCKS:bool>
    <(HSC.Content)>
    </$macro>
    
    <NOSIMON>
    <SIMON-SAYS>use HSC!</SIMON-SAYS>
    </NOSIMON>
  2. Inner macro SIMON-SAYS inserted in outer macro
    <NOSIMON>
      <$if COND=(defined SIMONSUCKS)>
        Muhammad says:
      <$else>
        Simon says:
      </$if>
      use HSC!
    </NOSIMON>
  3. All expanded
    <$define SIMONSUCKS:bool>
      <$if COND=(defined SIMONSUCKS)>
        Muhammad says:
      <$else>
        Simon says:
      </$if>
      use HSC!

That's the whole trick. The final evaluation of the <$if> block will throw away the Simon part and we get the result we want.

Writing your own macros I suppose you'll generally want the second form using <(HSC.Content)>, because it works just the same for simple cases as decribed in "Defining your own logical styles" (although it may be slower; I don't have a CPU that would make this noticeable any more) but allows for a lot of tricks beyond that, most importantly macros that can access their "parent's" local variables and even modify them. This mechanism will be used ad nauseam in the part on semi-automatic layout, once I get around to writing it :) However, using this may make debugging your HSC code more difficult, because you can get very long "backtraces" for every error, indicating every nested level of expansion1.


Footnotes
  1. See HSC's documentation on the NONESTERR parameter!

Last change: 21-Feb-2006, 06:43

You are not supposed to see this—arachnoids only: nude metal goth porn tits video i phone thai hentai gangbang girls i touch lolita emo slutsparis ghettoschlampen arschgeficktgay geigh salope enculée pédé