Variable substitution within \procedure or \define

I’ve just found out the hard way that variable substitution are occurring within \define where they should not and not eleswhere and especially not within \procedure.

The code:

\define buggy()
  <ol>
    <$list variable=hole filter="[prefix[sub]]">
       <$let part01 = {{{ [[insert $(hole)$ @$(currentTiddler)$]] }}}
                part02 = {{{ [[insert $(hole)$ @$(currentTiddler)$]substitute[]] }}}
          >
	    <li>part01: <<part01>> THEN part02: <<part02>></li>
          </$let>
	</$list>
	</ol>
\end


\procedure correct()
  <ol>
    <$list variable=hole filter="[prefix[sub]]">
       <$let part01 = {{{ [[insert $(hole)$ @$(currentTiddler)$]] }}}
                part02 = {{{ [[insert $(hole)$ @$(currentTiddler)$]substitute[]] }}}
          >
	    <li>part01: <<part01>> THEN part02: <<part02>></li>
          </$let>
	</$list>
	</ol>
\end

!! buggy
<<buggy>>

!! correct
<<correct>>

Try it on tiddlywiki.com on a tiddler named “bug” and see the below output:

=======
buggy

part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug
part01: insert @bug THEN part02: insert @bug

correct

part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert subfilter Operator @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert subfilter Operator (Examples) @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert substitute Operator @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert substitute Operator (Examples) @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert subtiddlerfields Operator @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert subtiddlerfields Operator (Examples) @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert subtract Operator @bug
part01: insert $(hole)$ @$(currentTiddler)$ THEN part02: insert subtract Operator (Examples) @bug

=======

In \define’ variable er immediately substituted but not with their values but with empty contents.

Hi @jypre variable substitutions like $(hole)$ are only performed within the body of a macro, and do not occur within procedures. (They are also used with the backtick substitution syntax, and the substitute operator).

In your macro example, the variable substitutions are performed before the macro is processed. At that point, the variables in question do not have values, hence the unexpected result.

Your procedure example doesn’t work because variable substitutions are not supported within procedures.

For a general audience;

  • I hope this may help @jypre but also the community
  • I also find it helpful to spell out what I have learned as well.

Given procedures are now recommended over macros, initially discovering we could only reference parameters as variables, and not as variable substitutions as we do in macros, I was quite concerned at loosing substitution.

  • We do need to manipulate strings quite often, so substitution is critical.
  • although concatenation is often sufficient eg addprefix

However I quickly discovered, we have being more than compensated for this loss in procedures of substitution, in addition to the fact macros are only deprecated and integrate well.

With parameters as variables, they can be used directly as we may have done in the past with <<__paramname__>> (in macros only) now we can use <<paramname>>, however using parameters in filters offers much more functionality because ,of various operators that can manipulate strings. We now have;

  • the new substitute operator
  • existing filtered transclusion of course
  • functions as an alternative way to process filters, thus variable parameters.
    • this is very comprehencive I wont detail here but importantly there result can be used directly in text and you can join[ ] in filters.
  • The new back tick attribute values, including access to the substitution of variables and filter results.
    • one advantage here is you can avoid seperate macro definitions and evaluate, concatinate and substitute a value inline.
  • Another feature that helps us in the case of substitution is surprisingly the $parameters widget, because unlike with macros where we had the parameters in the definition macroname(p1:"") and limitations when calling <<macroname p1:"limits to what goes here"> the parameters can be defined with the parameters widget and have their (the parameters) values evaluated there eg; the parameter value can be derived from;
    • text references
    • functions
    • macros
    • filtered transclusions
    • new backtick attribute values

Special note on $parameters widget

Because using the parameters widget we can evaluate a value to assign to the parameter inside our procedures we can easily give tiddler names, fieldnames, variable names and more as a parameter, then have the entry in the parameters widget evaluate it.

\procedure myproc(fieldname)
<$parameters fieldvalue={{{ [all[current]get<fieldname>] }}>
fieldvalue for <<fieldname>> is <<fieldvalue>>
</$parameters>
\end myproc

<<myproc myfield>>
  • The point is we can convert a parameter to its value in the parameters widget, so our short form of procedure call <<<<myproc myfield>> is simplified.
  • We can also reuse the same variable name in the parameter widget eg use fieldname in the parameters not fieldvalue.
  • I have not yet established a naming or code pattern standard for these names rather than values.
1 Like

@jeremyruston But my aim was not not have variable substitution, but to have written as is just in ordeer to be able to use the substitute operator.

In fact, I was aware oh parameter subsisution within macros and not of variable substitution (at least, when I encountered my problem).

Not that I complain about the new procedure. This is fine, just needing time to be used too. I progress in the matter.