Are macros, functions, procedures and widgets really synonyms for the SetVariableWidget?

The documentation says that macros, functions, procedures and widgets are synonyms for the SetVariableWidget. It in turn is just a synonym for the SetWidget. However, if I want to use <$set> directly, I don’t think I can set the isMacroDefinition, isFunctionDefinition, isProcedureDefinition and isWidgetDefinition that it uses internally.

(The context of my question is that I don’t like setting stuff at the top of a tiddler and use it at the bottom. Would much rather define things close to where they are used)

@jeremyruston suggested we may add/change those flags one day. It is a slight gap, but would also enable some interesting hacks changing the flags inline.

Just keep in mind;

  • Items set at the top of the tiddler get the scope of the tiddler, things defined later only have their scope to the close of that widget, and in some case auto closure occurs.
  • If it is aesthetics you are after, you could move the definitions to global functions with appropriate variables or parameters giving it the specific local values. The functions will just be used and need not be defined in the tiddler.
  • $set $let $vars can be seen as their true selves, using the internals plugin, preview widget as on Tiddlywiki.com
  • Have you looked at $importvariables?
  • Transclusions, even parametised transclusions can also be used to reference something external to the current tiddler, later in the tiddler, that never the less defines it in the tiddlers scope. The transcluded tiddler can contain pragma.
  • Did you know a custom widget defined inline can contain its own pragma, definitions at the top?

TLDR;

There has been some discussion at GitHub, to allow users to create procedures with the <$set widget, but it has not been implemented yet.

But even it it will be implemented in the futere, I doubt it will work in a way you expect it. We will need to keep the one parse run and the parent - child structure. – IMO mainly for speed reasons.


For some high-level languages it is OK to define variables near, where they are used, because it makes maintenance easier. But also there it depends on the usecase of the variables. – And most of those languages are compiled. So it is possible to do several parsing runs and compiling speed does not matter at runtime.

That’s different with wikitext. For speed reasons we can only parse the wikitext “code” in a linear run. So it is not possible to define a “tiddler global” variable at the end of the content and use it globally in the tiddler.

\function, \procedure, \define, \widget are pragmas and have to be at the top of the content for exactly that reason. – Parsing speed

I you have a closer look at the following code

\procedure outer() outer text
\procedure inner() inner text
\procedure innerMost() abcd

It will create a widget-tree as seen in the screenshot:

  • All 3 procedures are converted to set-widgets
  • outer is the first one and it has a children array
  • inner is a child of outer - and also has a children array
  • innerMost it a child of inner … and so on.

This makes sure, that body text can call them as macros. Because body text will be children of innerMost. That way, children do automatically inherit variables from their parents.

So looking up “global” variables is as simple as going from parent to parent and use the first variable name that fits.

The TW widget tree is very similar to the HTML DOM tree, which is no coincidence, since the goal is to create HTML as an output.

Conclusion: see TLDR;

Hope that makes sense
-mario

2 Likes

you can do this to define things in the middle of a tiddler like so:

!!internal defintion

<$vars y="and John">

$$$text/vnd.tiddlywiki
\define hi(x) hi to $x$
and say <<hi mat>> <<y>>

and the tid goes on

Sure, I understand things need to be defined before they are used, but not sure why it needs to be nested and why this nesting needs to happen at the top. Regardless, if the $set widget would allow to create macros, function, procedures and widgets (by having attributes instead of the isXXXDefinition ), then the nesting would be preserved, no? That is, the definitions will be visible only in the body of the widget. Further, it seems to me if you have a ‘$scope’ widget that creates a new scope, then you can have pragmas in it that will attach their definitions to the scope (well, the first will, the rest will be under its children lineage)

In fact, seems like $$$ does that, but in a non aesthetic way.

As I wrote, there has been some discussion at GH about that possibility. Sadly I can not find the discussion at the moment. Obviously it has low priority.

maybe this is a bit nicer

!!internal defintion

<$vars y="and John">

$$$text/vnd.tiddlywiki
\define hi(x)
 hi to $x$
\end
$$$text/vnd.tiddlywiki

and say <<hi mat>> <<y>>

and the tid goes on

@buggyj – see: https://tiddlywiki.com/#Typed%20Blocks%20in%20WikiText

The end-marker for typed blocks is $$$ So you did start a second typed block, which probably is not intended.

I did intend to start a second block, otherwise the macro would be out of scope.

indeed, with closing block it would be


!!internal defintion

<$vars y="and John">

$$$text/vnd.tiddlywiki
\define hi(x)
 hi to $x$
\end

and say <<hi mat>> <<y>>

$$$
and the tid goes on

This works! Thanks!.

That is very similar to transcluding a tiddler containing definitions, only its visible.