Frustrations of Wikitext from a Software Dev

I speak both English and French. As I speak in either of those languages, I’m also thinking in the language I am speaking. Otherwise, I find myself translating in my head, and the results can be pretty screwed up.

Same for TiddlyWiki. You have to think in that language. Or a language that is very similar.

When it comes to TiddlyWiki programming, you will have better success if you think as you would writing SQL (and thinking relational algebra), than if you are thinking C/C++/javascript/java/fortran/rust/whatever.

If not thinking as you would when writing SQL, then thinking as you would when writing APL.

Think in a series of transformations from the raw stuff you have at the beginning to the end result you want.

I can’t explain it beyond that. Too complicated to explain.

3 Likes

Is the distinction you’re making here between an imperative style (do this, then do that, then do the other thing) and a declarative one (give me output like this, however you need to implement it?)

I write mainly in JS these days, front and back end. I write mostly in a functional paradigm, which is much closer to the declarative mindset. But I still find myself facing the same issues @GameDungeon describes. That is improving with experience, but comes back frustratingly often.

Or did you mean something else more specific to SQL, something that might not apply to things like XSLT or Haskell or LISP?

In this case, then, I think some confusion came from the word “Function” I originally asked why WikiText didn’t have something like a function instead of just macros. That’s where the security reasons thing came up. I was not referring to JS, I meant within wikitext itself.

Having the ability to run some code and return a value is surprisingly valuable. Just as the first example that comes to mind, in a macro-only language, you lose entirely the ability to use recursion.

Honestly the fact that someone has to show me to use wikify is a failure on the language’s part. It’s entirely unintuitive. Maybe I do have the wrong mindset, but it’s a mindset that comes from experience with software, and as far as I can tell, one not at all challenged by the docs. Above charlie says I have to think in the language. I can’t think in a language I don’t understand. The docs give me a vocabulary without teaching me grammar. It just comes out as a word soup.

Wikify shouldn’t exist. This post partially exists because of me. The author was finally pushed to write it, by my complete failure to understand what it actually does. I still don’t really understand what it does. Why can’t I use “the output of widgets in a filter expression?” Wikify feels like a patch over a hole in a language, and a patch I’m told not to use, as it’s “slow.” It’s also a patch that without someone explicitly telling me about it, I would never even think to use, I’d probably never even guess it exists. Honestly, short of bashing your head against the wall for a while, it’s hard to even tell that a hole is there. “Maybe I’m just typing this wrong?”

Maybe this just sounds crazy, trying to catch an emotion of frustration, and then discontent upon hearing the solution and putting it into words.

This is curious to me because it is just incorrect, unless you are using one of these terms differently to me, or you are referring to the specific case where if you don’t wikify something it breaks.

  • Frankly I totally agree, I have stumbled on this a number of times and just in time wrapping something with a widget so that a variable is treated as we expect it to, that is, to return its a value, not the code that determines value, is next to silly even if there is a historical justification. This is however an “edge case”.
  • I have endeavoured to have this at least simplified down to some custom delimiters without success.
  • As you say, the other problem is we are readily discouraged from using wikify whilst at the same time there are some cases where it is the only option.

Although not withstanding my above agreement with you on wikify @GameDungeon there are a few reasons in my view why you may have problems initially becoming proficient in tiddlywiki, some that effected me as well.

  • If you are familiar with procedural programming you may come unstuck because the way tiddlywiki is implemented is more like a 4th generation language, List Processor.
  • If you are familiar with object oriented programming you will get a little stuck because the objects are outside the code, they are tiddlers.
  • Both procedural and Object oriented programmers get stuck somewhat because the rendering is handed over to the tiddlywiki core to handle.
    • You need only do part of the work, tiddlywiki does the rest.
  • Another thing is how somethings need a trigger and others handled automatically.

I personally had the advantage of starting with TiddlyWiki Classic v2.x , where to do anything sophisticated, you had to understand the architecture and the place of tiddlywiki’s role in keeping the whole wiki up to date (in a very efficient manner) and the final render process.

  • A technical summary of this, although aging (2014) can be found here

Where tiddlywikis architecture is difficult for programmer’s to come to terms with, I believe it is much easier for non-programmer’s to come to terms with tiddlywiki than most program languages. Remember we did not know programming until we learned it.

The truth is what we already know can make an “Ass out of U an ME” - ASSUME, assuming and part of tiddlywiki is unlearning some things.

  • Pity we cant use Spock’s mind melding technique.

What you see as an end result in a tiddler, is the sum of things that take place as a result of a number of different and sometimes sophisticated parsing processes that TiddlyWiki does for you. Not the same as what you are accustomed to in many languages. In part this is because its all built inside a HTML document.

I hope this helps

2 Likes

Just a short statement: I love Wikitext.

This is not true!

Recursion is used in the TWCore toc-* macros (see $:/core/macros/toc), which does a depth-first recursive “tree walk” based on tags. Another example can be seen in the TWCore tree macro (see $:/core/macros/tree), which produces a depth-first recursive tree walk of system tiddlers by splitting tiddler titles using “/” as a separator.

Note that neither of the above examples use the $wikify widget since they produce direct output in a wikitext context.
It is only when we need to “capture” the output for further processing that $wikify comes into play.

For example, I’ve written a recursive <<toc-list>> macro that works similarly to the TWCore toc-* macros, but produces a flattened list of tiddlers, rather than outputting an indented tree view. Let’s suppose we then want to navigate through this flattened list using first/previous/next/last buttons.

Note that I previously posted an example of this type of navigation using a filter that finds all tiddlers that have a field named seq that contains a “sequence number” that defines the order of the tiddlers to be viewed. (see Next / Last functionality using fields - #2 by EricShulman).

Here’s a variant of that wikitext navigation code, using a list generated by my recursive <<toc-list>> macro to perform sequential navigation, starting from a “root tag” tiddler (e.g., “TableOfContents”):

<!-- RECURSIVE TREE-WALK TO GENERATE A FLAT LIST OF TIDDLERS -->
<!-- USE OPTIONAL "max" PARAM TO LIMIT THE DEPTH OF THE RECURSION -->
<!-- "exclude" IS AUTOMATICALLY COMPUTED TO AVOID INFINITE RECURSION CAUSED BY "TAG LOOPS" -->
\define toc-list(here,max,exclude,level:"1")
<$list filter="""[tag[$here$]] $exclude$ -[[$here$]]""">
   <$text text="[["/><<currentTiddler>><$text text="]]"/><br>
   <$reveal default="$level$" type="nomatch" text="$max$">
      <$macrocall $name="toc-list" here=<<currentTiddler>> max="$max$" exclude="""$exclude$ -[[$here$]]""" level={{{ [[$level$]add[1]] }}}/>
   </$reveal>
</$list>
\end
<!-- UTILITY MACRO TO OUTPUT THE BUTTONS -->
\define go(label) <$button> $label$ <$action-navigate/></$button>
<!-- GET THE FLAT LIST -->
<$wikify name="tids" text="<<toc-list 'TableOfContents'>>">
<!-- MAKE SURE THE CURRENT TIDDLER IS IN THE LIST -->
<$list filter="[enlist<tids>match<currentTiddler>]" variable="curr">
<!-- OUTPUT THE FIRST/PREVIOUS/NEXT/LAST BUTTONS -->
<$list filter="[enlist<tids>first[]!match<curr>]"><<go first>></$list>
<$list filter="[enlist<tids>before<curr>]"       ><<go prev>></$list>
<$list filter="[enlist<tids>after<curr>]"        ><<go next>></$list>
<$list filter="[enlist<tids>last[]!match<curr>]" ><<go last>></$list>

To see this code in action on https://TiddlyWiki.com, just copy/paste the above code into a tiddler (e.g., “TOCNav”), and tag it with $:/tags/ViewTemplate. For each tiddler in the TableOfContents, navigation buttons will appear at the bottom of the tiddler.

4 Likes

As Eric notes, it works fine.

\define recursion(string) 
<$list filter='$string$ +[split[]butlast[]join[]]'>
{{!!title}}
<$macrocall $name=recursion string={{!!title}} />
</$list>
\end

<<recursion recursion>>
1 Like

Recursive macros work perfectly fine … One of the famous examples for recursive code is the Fibonacci series.

So the spec is: Print all Fibonacci numbers below 1000.

The code looks as follows. I call it “macronacci” in short “m” since it does not force us to start with 0, 1, 1, 2 … It allows to start with any number n1 and applies the same rules as the Fibonacci series does.

It also has a sep-parameter to define the separator between the numbers. This comes in handy if we want to make the list more readable. eg. linebreaks instead of spaces

\define m(n1:0 n2 sep:" ")
<<__n1__>><<__sep__>>
<$let n1={{{ [<__n1__>match[0]then[1]else<__n1__>] }}}>
  <$let n1={{{ [<n1>add<__n2__>] }}}>
    <$list filter="[<n1>subtract[1000]sign[]match[-1]]">
      <$macrocall $name=m n1=<<n1>> n2=<<__n1__>> sep=<<__sep__>> />
    </$list>
  </$let>
<$let>
\end

<<m>>

The output is

This works perfectly fine. The $macrocall widget is used to call the “m” macro recursively.

Instead of only calculating the numbers with the line <$let n1={{{ [<n1>add<__n2__>] }}}> we could also calculate the quotient for n1/n2 which works by replacing the old formula with the following lines. The quotient should converge against the “golden ratio” which is 1.618033

  <$let n1={{{ [<n1>add<__n2__>] }}} quotient={{{ [<__n1__>divide<__n2__>precision[6]] }}}>
| <<quotient>><br>

As I wrote TW is all about creating lists to “draw” content.

BTW we use recursion often eg: The table of content and the tree macros use recursive code.

2 Likes

Hi @GameDungeon,

Let me offer my understanding of Wikitext after many years of using TiddlyWiki.

I believe that your frustration comes from overlooking that a wikitext program is mainly aimed at asynchronously displaying HTML code in the user’s browser, in adequate response to user actions.

  • Widgets are responsible for storing this code into tiddlers (usually upon interaction with the user), some of which may get displayed immediately, others just holding the code lazily, some just recording a state.
  • Filters are the closest things to functions. They are the most powerful way to compute results in an ever refreshing environment (once again due to unpredictible user interactions). Before being synched into tiddlers, these results are usually assigned to variables or widget attributes.
  • Macros are primarily a way to store text or code snippets to be reused at will by widgets or filters.

What about the <$wikify/> widget? It is a very special widget that can be used to capture the text that would otherwise be computed by the display engine, in order to produce immediately usable code. For instance, say you like metaprogramming and you want to compute a filter string based on specific user interactions, and use this filter right away in your code : in such cases, it is handy to store the “ready to print” result of your computation into a variable, thanks to <$wikify/> and reuse this as a subfilter. Certainly not for the everyday use.

2 Likes

I’ve been thinking about that a lot. I’m asking myself how I would document TW so that it would be comprehensible to someone who thinks like me. So now I’m asking you, @GameDungeon. I’m assuming you’ve made some progress and it’s not all still mysterious. How would you document what you know?

I’m hoping to start writing such documentation in six or eight weeks when some of my other work should slow down. I have no idea how to present it, or if what I eventually do might be useful on tiddlywiki.com, but I would start entirely separate. If you have interest in contributing, please let me know.

(And feel free to reach out to me out-of-channel. scott@sauyet.com.)

2 Likes

Acturally we have write many tutorials in Chinese tw-cn.netlify.app/ to cover conercases like:

  1. using transclusion in filter
  2. using filter in transclusion
  3. using variable in filter
  4. using xxx in yyy

and

  1. get wikitext variable in js side
  2. send message from wikitext to js
  3. call wikitext widget from js side
  4. xxx wikitext from/to js side

I think with these knowledge, wikitext is just like simple JSX in React.

2 Likes

Well if I could easily describe it with labels, I would have described it with labels.

None of the labels describe it.

The difference is like the difference between one spoken language and the other, and the ability to fully transition from one to the other such that you are thinking in the same language you are speaking.

Imagine somebody speaking Spanish with French accents on everything instead of Spanish accents, and English sentence structure all over the place instead of Spanish sentence structure.

TiddlyWiki programming, the thinking is more like SQL programming for the person who has mastered SQL programming, and thinks SQL programming as per the math behind it.

So many great Zen stories that would fit, like:

The Zen teacher’s dog loved his evening romp with his master. The dog would bound ahead to fetch a stick, then run back, wag his tail, and wait for the next game. On this particular evening, the teacher invited one of his brightest students to join him – a boy so intelligent that he became troubled by the contradictions in Buddhist doctrine.

“You must understand,” said the teacher, “that words are only guideposts. Never let the words or symbols get in the way of truth. Here, I’ll show you.”

With that the teacher called his happy dog.

“Fetch me the moon,” he said to his dog and pointed to the full moon.

“Where is my dog looking?” asked the teacher of the bright pupil.

“He’s looking at your finger.”

“Exactly. Don’t be like my dog. Don’t confuse the pointing finger with the thing that is being pointed at. All our Buddhist words are only guideposts. Every man fights his way through other men’s words to find his own truth.”

A Taoist story tells of an old man who accidentally fell into the river rapids
leading to a high and dangerous waterfall. Onlookers feared for his life.
Miraculously, he came out alive and unharmed downstream at the bottom of
the falls. People asked him how he managed to survive. “I accommodated
myself to the water, not the water to me. Without thinking, I allowed myself
to be shaped by it. Plunging into the swirl, I came out with the swirl. This is
how I survived.”

1 Like

If you are getting frustrated, then the depth and breadth of your software development experience might be getting in the way.

It could be you have fallen into something akin to getting upset at the green bean plant for not producing a tomato despite you doing all of the things that would help grow a tomato.

Know what it is, and do as it needs. Think as it is.

Detach yourself from all you know that is software dev. Detach yourself from expecting TiddlyWiki programming to behave like anything you’ve known.

Get rid of your expectations. You are not going to get tomatoes out of that green bean plant.

Exception: if you can think SQL correctly (i.e. you are at one with the math of SQL), then think SQL and that will be helpful.

Learn to walk before you run. Learn to crawl before you walk.

There are some very tiny things from your software development experience that will be of use. You’ll know when they are of use as you know TiddlyWiki programming.

If that widget did not exist, BASIC Anywhere Machine would cease to work.

You’ll get to where you want to be much quicker if you lose your expectations. A small amount of the baggage you carry might be useful, but much of it you need to toss.

That worked for me. It will work for you. Be as water, not as rock.

Aside: documentation and the community refer to the language of TiddlyWiki as “WikiText”. I loathe that moniker. I much prefer “TwScript”. To me, “WikiText” is the markdown language of TiddlyWiki, that makes things bold/underline/italic/etc.

Loads of words tossed around that aren’t necessarily universally appealing from a semantics/cognitive perspective.

For what it’s worth, tiddlywiki didn’t invent the term wikitext, mediawiki did: Help:Wikitext - Wikipedia

Yeah, that’s largely what I consider to be WikiText. The other parts of what folk call TiddlyWiki’s “WikiText” I don’t call WikiText. I call TwScript and TwQL, Pragmas, and Controls (i.e. the GUI objects like buttons etc.).

Something like that. The categories help with my understanding of TiddlyWiki.

3 Likes

Side note: It is easy to say “someone ought to” but… someone ought to make an introductory writeup about these things, specifically addressing developers. I’m personally not qualified to do it (I’m not a developer) but from this discussion it seems that many developers (most? just a few?) come with a different frame of reference and false assumptions.

Consider that sw developers are, potentially, among the most important people we can get as community members.

2 Likes

Where I was wrong about macros, is because the macros in TW don’t exist as preprocessor macros, but are something more live. I feel kind of dumb for not realizing that. I do notice, that for the most part that one sentence was the only thing actually addressed.

I’m not sure anybody mentioned it in this thread: Probably in the very next update to TW there will be new mechanisms that make macros much more similar to functions.

1 Like

Oh heck no, I don’t see it as you being wrong.

More lead astray by both from-experience-preconception of “macro” and documentation that isn’t quite as clear as it could be. (That’s the nature of documentation: not an easy thing to do.)

That’s the problem with words. They often already have a meaning in a certain context. To reuse the same words to mean something else in a different context, that gets confusing.

Like the word “widget”. Totally throws me off my game. So I don’t use that word anymore.

Instead: “GUI Controls” (or “Controls” for short) and TwScript. I need my tidy groupings…

1 Like