How to add "comments" to filter expressions

@bluepenguindeveloper That’s a rather sweet approach. :clap:

Perhaps post a github request for this capability, though I’d make it noop[my comment] which amounts to a constructor when in zeroth position, and a pass-thru when found elsewhere.


noop for those that aren’t aware, is a well-known term in programming for a benign “no operation” function/procedure.

1 Like

I personally don’t see the need to add a “noop” operator to TiddlyWiki, since with the ability to define your own functions (linked for anyone unaware), you could just do this (at the top of a tiddler tagged $:/tags/Global):

\function .noop() [all[]]

(For those who don’t know, the all[] operator with an empty parameter simply returns a copy of the input. You could also use [addprefix[]] or some other method of performing no change to the inputs. Extraneous parameters are ignored, but if you like, you could add a dummy parameter to the function.)

But maybe :noop filter run prefix with a nice unused shortcut such as # could be a nice alternative to using -.

{{{
  #" (Explanation of the entire filter expression)"
  [all[tiddlers+shadows]tag[spam].noop[##get everything tagged "spam"###]]
  #" Next we use :filter to filter out those tagging more than 3 items "
  :filter[tags[]count[]compare:integer:gt[3]]
  #"...(other steps)..."
}}}
3 Likes

Excellent. I’m liking this a lot. :trophy:

EDIT: I just bookmarked your post – something I rarely do :blush:

1 Like

Variant, just tried this proof of concept at TiddlyWiki.com:

I like hyphen on each end, so comment has symmetrical look.

As long as there are no spaces in the string, you can use whatever colorful emoji or symbols you like, to help the comment strings stand out visually, or give an iconic clue about the filter step in question. (The comment with heavy concave brackets, toward the bottom, looks like it has extra space, but the space is part of the symbol.)

:slight_smile:

3 Likes

I found this issue on comments in filter expressions, so I left a comment there suggesting a :noop prefix with a shortcut. But it’s an old issue, so if I don’t see any responses in a few days, I’ll go ahead and open a new issue.

1 Like

This, if used without a corresponding filter run prefix (e.g. +) will output all tiddlers in a wiki, since those are the input to a filter run without a constructor as initial operator.
Try this in a new tiddler on tiddlywiki.com to see what I mean:

\function .noop() [all[]]
<$list filter="[[HelloThere]] [.noop[This is a comment]]" />

@CodaCoder got it right. I’m not sure that you can put the necessary logic into a single function definition. I do like the idea of a :noop filter run prefix, though, since this way we don’t have to make the constructor/modifier distinction.

:+1: Thanks. Full disclosure, it was your XXX/Debug filter that got me thinking about this. My initial thought was to tag you and ask that you provide a noop suffix to your filter… but then I couldn’t see how that might work in a useful way. :confused:

Ah, now I see why @CodaCoder mentioned it being a constructor in the zeroth position. Though I think this could just as easily mess things up in the opposite way. For example:

[noop[This run does so and so (explanation of the run)]tag[eggs]!has[spam]]

If you design noop to be a constructor outputting nothing if given as the start of a filter run, then inserting it at the beginning of a filter run changes the outcome of the filter run (and therefore is not a noop).

You might say that in such cases you should separate it into its own run:

[noop[This run does so and so (explanation of the run)]] [tag[eggs]!has[spam]]

I might just as easily say that if you’re using a custom .noop in its own run, you should make it a + run or add it to the end inside the previous run ([[HelloThere].noop[comment]]). (Or, if provided at some point, a :noop prefix.)

I’d be surprised if you could even put the necessary logic into a JavaScript-defined filter operator without significant changes to how filter runs work. I would’ve assumed that, even defined in JavaScript, the filter operators don’t know their positions in the run, and are only given a list of inputs to manipulate. But someone who knows the code could tell us for sure. Are there any other filter operators that behave differently depending on whether they are the first operator in the run?

This is the closest I could find, but it’s not what you’re looking for:

The subfilter operator will act as a constructor whenever the filter defined by its parameter is a constructor. Otherwise, it will act as a modifier.

I don’t think operators are aware of their position, either. A filter run is always given all[tiddlers] as its input. The operator then decides if it ignores it (constructor) or uses it (modifier). This would be hard-coded in the operator JS. A filter run prefix that doesn’t modify the previous results in any way seems to be the safest approach.

I think so too.

I’m not opposed to a noop operator, but I think if we get one, and especially if we get both the operator and the prefix, then the noop operator should always act as a passthrough regardless of the position. My reason is from these examples:

From these examples, it seems that we want the “noop” operator to act as a constructor not when it is the first operator, but when it is the only operator in the filter run. But if it’s the only operator in its run, then what we want is for the whole filter run to be a noop, in which case a filter run prefix is more appropriate than an operator.

Whereas if it’s not the only operator in the run, then it should be a passthrough.

In short, when we want a separate filter run to be a noop, we should use a noop filter run prefix, and a when we want a noop inside some other filter run, we should use a filter operator that returns its inputs unchanged.

(And for operator, \function .noop() [all[]] does the trick.)

14 posts were split to a new topic: Filter Comments Proposals

Yes, when it has need to add comment, where readability matters, it won’t still write one-liner.

It is a nice idea – but

The main problem I do have with an :except filter run prefix as comment is, that it is based on 2 potentially wrong assumptions.

  • No comment made, that way, will ever be a tiddler title
  • Users can identify the difference between an :except filter run and a comment

This assumption will fail whenever comments get shorter. eg: -[[TODO refine]] – There is a high chance that this “comment” will be a valid tiddler in the future.

There is no chance to see, that it is a comment, even used like this -"TODO refine". I personally do use single double-quotes in some filter expressions.


This was the main reason, why I immediately did create a proposal and 2 different PRs at GH.

Especially, since Jeremy already created an issue 2 years ago.

So there is a high chance, that one or the other version will be pulled into the core.

True, and a proper comment will be better for this reason, and I look forward to any true comment feature introduced. (I would actually like to get both the line break-terminated and a filter run prefix version for multi-line comments.) But until then…

It’s also worth noting that one could mitigate the risk in those assumptions by always writing comments with some style that they also never use in tiddler titles, for example, a ### prefix, which also makes the comments look distinct from an :except filter run.

[Edit: by “a ### prefix” I don’t mean a filter run prefix, I mean writing comments like -"### comment".]

(Or as stated in the OP, if you need it to be absolutely foolproof, you could use = instead of - and add +[butlast[]]. I personally don’t recommend this simply because I think it would be a pain to add all the time, and potentially distracting.)

Surely another reason ### appeals is because of how easy it is to scan for it. That’s why I have been playing with comment-hack variants that dramatically stand out, visually. If you resolve not to allow spaces in your comments (or use non-breaking spaces), then you don’t even need quotes or square brackets. And you don’t need the bookend comment-ender, though I love the symmetry, myself.

{{{ [tag[Concepts]]
    -🟥Start_with_tag🟥-
:filter[length[]compare:integer:eq[8]]
    -🟥Allow_only_8-char-long_titles🟥-
}}}

A solution like this wants a “stamp” or handy copy-paste shortcut (since the red box is not easy to type), but it stands out visually, and there’s zero chance of my accidentally having tiddlers with titles like this.

I love that this can be done right now, without waiting for any changes to core!

1 Like

My example is similar, but has the advantage of eliminating blank entries that sometimes occur;

\function no.op() [!is[blank]]

Interesting approach, consider this;

\function .🗎(note) [!is[blank]]
\function .#(note) [!is[blank]]

{{{ [tag[TableOfContents].🗎[note to self]sort[]] }}}
<hr>

{{{ [tag[TableOfContents]sort[].#[note to self]] }}}
  • Unlike yours the notes need to be inside a filter run.
  • And Spaces are fine, because its a parameter that is never used.
  • [all[]] can also be used as suggested by @bluepenguindeveloper
  • A javascript # filter operator would be better than .#
    • Or consider #.① …②③④⑤⑥⑦⑧ #.⑨ or #.⑴ …⑵⑶⑷⑸⑹⑺⑻ #.⑼
    • Then later <!-- #.⑨ this filter is for ... -->

In my mind, this is an operation that is sometimes desired and sometimes not, and should not be baked into a comment.

I have never wanted to see blank values only hide them, so to me it is a positive, but as discussed its a simple matter of using your [all[]] instead of [!is[blank]]

  • A key here is they are both simple to implement and use, both look the same where they are used.
  • Both allow a note within a run, or in an additional run.
\function .🗎(note) [!is[blank]]
\function .#(note) [!is[blank]]
\function .note() [all[]]

{{{ [tag[TableOfContents].🗎[note to self]sort[]] }}}
<hr>

{{{ [tag[TableOfContents]sort[].#[note to self]] +[.🗎[message]] +[.note[other message]] }}}

Another observation

In Any filter that does not use more than one parameter, we can use a missing one to add a note. So this metyhod allows a remark agains a specific operator, a filter run, or for the whole filter.

{{{ [tag[TableOfContents],[🗎List of top level TOC tiddlers]] }}}

{{{ [tag[TableOfContents]sort[],[🗎A-Z sort of top level TOC tiddlers]] }}}
  • In the above I start with a symbol to make it obvious.

Conclusion

I think this is an answer to the original topic @bluepenguindeveloper ?, without any changes. Do we need a de facto standard or “just do it”?

Although more often than not other forms of comments may be better.

If I understand your point correctly, I agree - both as regard to the removal of blank results and as regards almost every other difference noted among the different options here, each person can use what they like best. (This is of course for comments that can be written without any changes to the core.)

And I do like how much we’ve built on one another’s ideas in this topic.

Here’s one more idea: undefined variables will be empty, and can be used in place of empty parameters.

[tag[Table of Contents]sort<#Some comment can go here#>]

Or extra/missing parameters as @TW_Tones said, but with <variable> syntax to make them look more distinct:

{{{ [tag[TableOfContents],<#🗎List of top level TOC tiddlers#>] }}}

(You could of course use {} as well.)

There is an idea about using hash # tags, extending your idea <#todo notes> could in fact be a hash tag #todo, the # is something you do not use as a variable, procedure or function so that it always returns nul, but it could be used as an attribute say to a hash tag procedure <<# todo>> that lists all tiddlers containing the hash tag #todo.

  • Observation, hash tags work here :nerd_face:

[Edited] If you place <# message here> or <#hashtag message here> in any non-existing parameter, of any filter operator it will make no difference and the content is not limited much; Only <>[]| cause a problem sometimes;

{{{ [tag[TableOfContents],<# "note" [[to]] [[ ]] {{ }} !>] }}}

Thus for reoccurring or reusable comments you could use #n as discussed above, to save repeating yourself, and if necessary turn it into a visible note;

\procedure #1() all contents below
\function #2() "More notes"

{{{ [tag[TableOfContents],<#1>] }}}

<<#1>>

{{{ [tag[TableOfContents],<#2>] }}}

Show #2: <<#2>>
  • We could even place a condition, eg a verbose switch, in the procedure.
  • Both procedures and functions (filters) offer different opportunities to include other content, that you can only see if used as a stand alone variable.