Functional programming: Transclusion vs. variables

I’m trying to understand the relationships between the different methods of substitution in TiddlyWiki.

I need to be confidently able to manipulate variables. Variables are the fundamental units of information that get rendered from one place to another. Most things in TiddlyWiki are actually variables.

  • Procedures are variables:

Procedures are implemented as a special kind of variable. The only thing that distinguishes them from ordinary variables is the way that the parameters are handled. ~ #Procedures

I understand that the angle bracket syntax denotes references to variables. In general, double angle brackets mean that some kind of variable is being rendered into the tiddler.

When I consider the problem of constructing strings from references to different tiddler data, I can’t fathom any way to do this other than by constructing a variable using procedures, functions, or macros. I’m pretty sure there’s another way to do this. I think you can transclude into variables somehow, but I can’t figure out how. I had a breakthrough last night when I realized that the reason why I’m struggling so much with TiddlyWiki is that I don’t understand functional programming structure. I think TiddlyWiki is a nearly pure functional programming environment. It is not very procedural and not very object oriented.

I think I have to construct my variables and I think the reason I think this is because I don’t know how to think some other way.

In my student project, I’m experimenting with functions and procedures because I need to construct strings using tiddler fields and filters. I want to post a difference in behavior between procedures and functions.

So, I go to the top of my tiddler and define function:

\function slug()
<$parameters tiddlerTitle={{!!title}}>
[<<tiddlerTitle>>split[—]first[]]
</$parameters>
\end

There are widgets, transclusions, and content in that tiddler. And then, somewhere in all the contents of the tiddler, I call the function by using the basic <$text> widget:

<$text text=<<slug>>/>

The output is the text “<parameters”.
Screenshot 2024-07-20 at 8.45.51 AM

What if I change the function into a procedure?

\procedure slug()
<$parameters tiddlerTitle={{!!title}}>
[<<tiddlerTitle>>split[—]first[]]
</$parameters>
\end

That outputs the whole <$parameters> widget.

That’s really intriguing:

  • Maybe the parameters widget isn’t supposed to be used in procedures as in functions.
  • The docs say that the parameters widget must be used “when the default value of a parameter must be computed dynamically”
  • It also says that the parameters widget defines variables for the transclude widget, the underlying mechanism, which “dynamically includes the content from another tiddler or variable”.

The reason that I tried <$parameters> inside the function/procedure experiment is that I can’t figure out how to substitute into the function/procedure/macro. I mean, I think I know syntactically how to do so, although the curly-brace transclusion syntax often confuses me. I’m pretty sure I’m radically over-thinking it, and I realized that the reason I’m overthinking it is that this kind of thinking is foreign to me.

Also, I suppose that widgets are actually “functions” in the sense of functional programming, i.e., in the sense of functions defined with Python’s “def” statement. (Of course, semantically within TiddlyWiki terms, functions are variables, as noted above, as clearly stated in the documentation.) I say this because widgets control substitution of data into other contexts where it does other things. I suppose that TiddlyWiki funtions and procedures allow some more procedural logic to be used in TiddlyWiki by allowing expressions to be directly built.

Quick note — you should hear more from a more advanced practitioner…

Within a filter expression, you get at your variable with only one pair of angle brackets, like so:

[<tiddlerTitle>split[—]first[]]

For the procedure, this now works:

\procedure slug()
<$parameters tiddlerTitle={{!!title}}>
<$text text={{{[<tiddlerTitle>split[-]first[]] }}}/>
</$parameters>
\end

<<slug>>

Functions are… a different kind of beast. I’ll pause here and let someone else continue…

I do not want to answer your above questions one by one, but I like to give you a rather old reference (not covering all features of TW 5.2.x and 5.3.x) which may help you alot

  1. See how brackets are used in WikiText and Filter Expression.
    https://kookma.github.io/TW-Scripts/#Shorthand%20Syntax%20Summary

  2. Start reading the examples in TW-Script, it gives you some real world example with explanations. (You may open Contents tab in the sidebar and select examples)
    https://kookma.github.io/TW-Scripts/

  3. Explore a comprehensive guide at Grok TiddlyWiki for an in-depth understanding of TiddlyWiki, complete with detailed explanations, practical exercises, and reviews.
    https://groktiddlywiki.com/read/

NOTE
You have syntax errors in your scripts (these are the source of errors in your above scripts)
For example, Functions are variable to keep filter expressions nothing else
Or variables inside filters have single angle brackets not double angle brackets

2 Likes

It’s a complex question. So first here is some code that may work for you:

\function slug(title) [<title>split[-]first[]]

<$transclude $variable=slug title={{!!title}}/>

or

<$transclude $variable=slug title=<<currentTiddler>>/>
  • Functions are like filter runs So your [<<tiddlerTitle>> notation is invalid. It would need to be: [<tiddlerTitle>
  • Functions can not have a <$parameter > widget inside their code block. They are “filter strings” only.
  • Functions only return the first element if the filter string would actually create several elements.

There will be a second post, but I have to think about that one.


Probably related: TW Variables Have a Scope and can be "Stacked" – Not sure if that one will help you.

1 Like

Thank you for the great replies, I’m exploring all of this and I want to show the result of throwing @Springer’s procedure into my tiddler and outputting the text widget.

I see now that the double angle bracket syntax, at least as a widget argument, outputs the content of any kind of variable verbatim without further rendering.

<$text text=<<slug>>/>

This produces:


That’s the parameters widget, which is the entire internal contents of the procedure.

But if I use the text widget with only one angle bracket around the call to the procedure-variable, it only outputs the word “true”.

<$text text=<slug>/>

Screenshot 2024-07-20 at 11.26.37 AM

This is very interesting.

I guess it evaluates to “true” because the variable exists.

That’s right, but can only be used in procedures. If you need a dynamically created parameter for a function you’ll need to do that with the “function call”. In my example I used:

<$transclude $variable=slug title={{!!title}}/>

I think you are right. You probably think too much :wink: TiddlyWiki is a big text-substution engine, with the purpose to create HTML code, which can be rendered by browsers to show some text.

From a “programmers” point of view, calling a “procedure” does not calculate the “value” of the procedure and return text. Instead it returns the whole code of the procedure into the place in the wikitext, where you “called” it.

Example:

My name is Mario

Is a bit boring. What if I want to make the wikitext more flexible. So “Mario” should be changed to “Paul”, without duplicating My name is. OK we use a procedure with some text and a “placeholder” variable.

\procedure showName(text) My name is <<text>>

<<showName Paul>>
<<showName Mario>>

Now TW does some it’s magic. You found out already, that internally everything in TW is “converted” to variables, widgets and transclusions.

There are 3 steps involved.

  1. Parsing wikitext, which creates an internal parse-tree, which can be cached for speed
  2. Converting the parse-tree into a widget-tree
  3. Rendering the widget-tree to HTML code

Let’s have a closer look at 2. The widget-tree that we get from our example code. Reduced to 2 lines for better readability.

\procedure showName(text) My name is <<text>>

<<showName Paul>>

Widget Tree

  1. The \procedure definition internally is a <$set widget with attributes name and a value
  2. <<showName Paul>> is a transclusion with the procedure “name” → $variable=showName and attribute 0=Paul
    • That’s a shortcut for <$transclude $variable="showName" text="Paul" />
      2a) We have a HTML P(aragraph) element
  3. Inside P there is a text-node: My name is
  4. a tansclusion for the <<text>> variable which comes as the procedure attribute.
  5. and the final text node Paul

As you can see at 2) It does not return the “finished text”. It creates more “child” widgets.

  • The P element 2a)
  • A TEXT node 3)
  • An other transclude widget 4)
  • An the final text node 5)

I hope that makes some sense
-mario

That’s invalid. It has to be <$text text=<<slug>> />true is the default value, if there is a parameter, where the widget can not make sense of.

So far I’ve realized two things based on this material:

  • The “programming side” of TiddlyWiki, though an obvious part of it that I think nobody would ever imagine trying to hide, is more separated from its own interface and the intended design patterns of using TiddlyWiki than I had thought.
  • I neither need to substitute variables into macros nor construct them with procedures, necessarily, if I can just transclude the right tiddler fields in the right contexts.

That’s another piece of the puzzle that has just come into place. I could get the title into a procedure and then act on it with expressions that way. That’s one option. Thanks for the great explanation!

So, the widget tree shows me that I can get the data types that I need from other things by manipulating the object model—it’s not as different from the DOM and is in fact used to build the DOM, as was explained previously.

Even so, because the design patterns of the DOM and JavaScript and not really implemented into the general TiddlyWiki interface, one can’t expect to be able to work with widgets like DOM elements. For instance, a glance at wikitext with lots of curly-bracketed transclusions and widgets can make one think that you can basically push things around using some internal JavaScript thing like some specific version of JQuery or React. Despite superficial aesthetic similarities, and despite TiddlyWiki being of course built from JavaScript technologies, this is a rather wrong impression.

Good resources, thank you in particular for your commented examples. It’s hard to examine comments on TiddlyWiki code because we don’t really have a native commenting system other than HTML comments.

I noticed the little toolbar that you’ve placed at the bottom of your tiddlers, containing a few user commands such as the commenting feature. I’m curious regarding the method of templating for that. It does not appear to me that there are any custom templates added through $:/tags/ViewTemplate.

Then I found that you have another commenting system inside of TW-Scripts, a simpler one, which is one of the provided solutions.

I’m curious about a couple things:

  • You define a small macro to pass along the tiddler title and then modify it using the <$wikify> wrapper.
    → Oh, that’s the scope of the variable. Wikify makes a variable from the output of another widget. It seems that widget is called from the opening tag of the <$wikify> widget; it is not the entire content of that internal element inside of it. The closing </$wikify> tag simply defines the scope of the variable.
  • I’m guessing that this system uses a tiddler $:/temp/commentName to hold the other part of the new comment tiddler’s title. Maybe the purpose of using this configuration tiddler is to allow the user to modify the naming conventions by changing the content in there. … but no, on second thought, that doesn’t make much sense. It looks like it is instead a reference representing the newly created tiddler for the action widgets.

I noticed the little toolbar that you’ve placed at the bottom of your tiddlers, containing a few user commands such as the commenting feature. I’m curious regarding the method of templating for that. It does not appear to me that there are any custom templates added through $:/tags/ViewTemplate.
Then I found that you have another commenting system inside of TW-Scripts, a simpler one, which is one of the provided solutions.
I’m curious about a couple things:

  • You define a small macro to pass along the tiddler title and then modify it using the <$wikify> wrapper.
  • I’m guessing that this system uses a tiddler $:/temp/commentName to hold the other part of the new comment tiddler’s title. Maybe the purpose of using this configuration tiddler is to allow the user to modify the naming conventions by changing the content in there. … but no, on second thought, that doesn’t make much sense. It looks like it is instead a reference representing the newly created tiddler for the action widgets.
  1. The commensting system uses an official plugin from tiddlywiki called Comments.
    You can open ControlPanel-> Plugins->Get More Plugins and search for Comments and install it!

  2. The https://kookma.github.io/TW-Scripts/#Create%20a%20Simple%20Comment%20Button is a piece of script create a comment button (something different from the first)
    It is rather old code. $Wikify is dicouraged to be used in your script unless you have no other choice. In your question


\define mytitle() comment on {{!!title}}

\define create-commentTid()
<$wikify name="ctitle" text=<<mytitle>> >
<$action-createtiddler
$basetitle=<<ctitle>>
$savetitle="$:/temp/commentName"
relationship="comment"
parent=<<currentTiddler>>
/>
<$action-navigate
$to= {{$:/temp/commentName}}
/>
</$wikify>
\end

<$button actions=<<create-commentTid>> >
Click to make a comment
</$button>

You want to pass comment on {{!!title}} to $basetitle as attribute value! You have to render it, so wikify help to do that!
You cannot do like $basetitle="""comment on {{!!title}}""" as TW passes the raw text and ‍{{!!title}} is not wikified here.

A TiddlyWiki 5.3.x solution is shorter and does not need $wikify in this case. It uses

Substituted Attribute Values


\define mytitle() comment on {{!!title}}

\procedure create-commentTid()
<$action-createtiddler
$basetitle=`comment on $(currentTiddler)$`  
$savetitle="$:/temp/commentName"
relationship="comment"
parent=<<currentTiddler>>
/>
<$action-navigate $to= {{$:/temp/commentName}} />
</$let>
\end

<$button actions=<<create-commentTid>> >
Click to make a comment
</$button>
  • I’m guessing that this system uses a tiddler $:/temp/commentName to hold the other part of the new comment tiddler’s title. Maybe the purpose of using this configuration tiddler is to allow the user to modify the naming conventions by changing the content in there. … but no, on second thought, that doesn’t make much sense. It looks like it is instead a reference representing the newly created tiddler for the action widgets.

$:/temp/commentName is a temporary tiddler to keep the title of newly created comment tiddler to be used for next part: navigate to newly created commend tiddler:


<$action-navigate
$to= {{$:/temp/commentName}}
/>

What do you mean by “manipulate variables”? What are the manipulation activities?

That plug-in is a good enough solution in itself, good enough to warrant designing around it instead of trying to make something new for a limited use case.

Oh yes, that is elegant and preferable. I had forgotten about that feature, and then when I have just tried it I wasn’t sure how to fit it in to my current use case. It was not rendering for me. I ended up doing it like this (adapting other classmates’ code):

\procedure noteTitle(fullTitle)
  Annotation—{{{[<fullTitle>split[—]first[]]}}}
\end

<$vars index={{!!thread_index}} one="1">
  <$set name="selectedTiddler" value={{{[tag[conversation-message]nsort[created]nth<index>]}}}>
    <$list filter="[<selectedTiddler>]">
      <$set name="selectedTitle" value={{{[<currentTiddler>get[title]]}}}>
        Title of the selected tiddler: <$view field="title" />
        <br>
        Again, this time using the title variable: <<selectedTitle>>

        <$transclude $variable="noteTitle" fullTitle={{{[<selectedTitle>]}}} />

      </$set>
    </$list>
  </$set>
</$vars>

The line that achieves the result produces a link. I don’t know why it produces a link, and I don’t want it to. I wonder if I have an extra [] pair coming from somewhere or something.

\procedure noteTitle(fullTitle)
  Annotation—{{{[<fullTitle>split[—]first[]]}}}
\end

...
<$transclude $variable="noteTitle" fullTitle={{{[<selectedTitle>]}}} />

The titles of all my main content tiddlers have the same pattern They begin with two numerals, fulled by an em dash, followed by a phrase. This cuts out the phrase and just keeps the two numerals, affixed to “Annotation—” to name the note tiddler.

But in the rendered result, the numeral part of the name is a hyperlink. And only the numeral part. I don’t understand why.

Screenshot 2024-07-21 at 8.17.35 PM

Like, in psuedo-code:

<$set myVariable = selectedTidler[title]>
<$transclude getTitlePart(myVariable)>
<$finalVariable = myVariable + titlePart(annotation)>

Edit: I got it wrong; I posted an earlier iteration first and now corrected it. Previously the line was

<<noteTitle fullTitle: <selectedTitle>>>

And that doesn’t work. The <$transclude> version does work and creates the output described.

So sorry if someone was confused!

:+1:

(Random text to allow post.)

The thread of conversation is too long and complex for me to understand.

Probably because I can’t think TiddlyWiki using analogies like “functional programming”.

I think I’m also a bit confused by this part of the thread title: “Transclusion vs variables”, which had me thinking there would be a comparison of the two.

I’ll throw in a “just an aside” in case it is useful for newbies: variables aren’t always necessary for concatenation of values. Transclusion without variables are enough for “visual” concatenation.

Say you have a tiddler A with two fields, “b” and “c”.

The body of tiddler A can show the concatenation of “b” and “c” without any variable.

You could have, simply, in the body (I.e. the text field) of “A”:

{{ !!b }}{{ !!c }}

And if you want to show that info from “A” in tiddler “D”:

{{A !! b}}{{A !! c}}

4 Likes