Redefine function inline, missing feature?

I believe I have identified a gap in the current features of tiddlywiki in relation to functions.

Background

Functions can be defined using the \function pragma, and accessed as;

  • A variable <<functioname>>
  • A function in filters [function[functioname] and functionname[]
  • other places such as within the backtick attributes filter $(functionname)$ - ${ [function[]] }$

Functions can also have parameters and default values, but let us put them aside for a moment.

There is however no way to redefine them inline!

Variables

Functions are considered a form of variable and can be addressed as such. In such cases only the first value is returned, but even this can be changed using format:titlelist and join.

Variables can be defined with pragma and made global.

Regular variables can also be redefined in line with $set, $vars, $let and as the result of the $list widget (and possibly others).

Redefining functions inline

Lets say I have a globally defined function I will to use in a large number of filter, for example a default sort order.

\function .sort(default:"title") [sort<title>]

Thus standard filters could be written to include +[.sort[]]

  • This allows me to change the default globally

However

If I am using a filter making use of the above function there is no way to redefine it inline, although I could use pragma in a given tiddler, this will override the use of .sort[] throughout the current tiddler.

A non working example may be;

<$let .sort="[!modified[]]">
<$list filter="[.all[]tag[TableOfContents].filter[]] +[.sort[]]">

</$list>
</$let>
  • I understand this does not work and possibly why
  • Nor does it permit the parameters settings possible in the \function pragma

Conclusion

Perhaps we could have a widget $function or enhance the set widget so we can redefine a function inline, in addition to the current \pragma so designers can use a global function but locally, within that $function widget, redefine the function.

Eg Non working example

\function .sort(default:"title") [sort<title>]

<$function name=".sort" default="modified" definition="[sort<title>]">
<$list filter="[.all[]tag[TableOfContents].filter[]] +[.sort[]]">

</$list>
</$function>
  • A way to redefine multiple functions inline would be helpful.

Bigger picture

Perhaps a similar or related solution to also allow the inline redefinition of macros, and procedures could be very helpful.

After note:
There are other ways of making use of variables in functions that provide alternatives to this proposed approach, however I see value in the above as useful enhancement that would be inline with the way we use variables. I am not looking so much for a workaround, but a solution as proposed.

Hi @TW_Tones

Doesn’t the <$importvariables> widget provide what you ask ?

Fred

I someways, but in this case I would class it as a work around. You need to have those functions defined elsewhere and import them here. So to override an existing global variable you need to redefine it and import it. The same can be done with pragma in custom widgets, inside blocks and within tiddlers you transclude.

However when it comes to standard variables its simply a matter of using let, set, vars or the variable parameter on a list widget. That is you can not only modify it inline but the code that does it is also inline.

Although just as the import variables widget is complementary to the \import pragma I would like a $function (and $procedure and $macro version) for inline use.

I can see this…

<$function 
  .fn1=[stuff]
  .fn2=[things]
  .etc=[fiddlersticks]
>

But I don’t get what your default: is for (it’s been a long day, maybe I’m not awake enough).

Ok, You got the param/

Here is an example of the procedure for redefining the .first function. I am not sure how to do multiples except nested like $set .

\function .first(prefix:"top - ") [all[tiddlers]first[]addprefix<prefix>]

{{{ [.first[]] }}}

<$function name=.first prefix="top - " definition="[all[shadows]first[]addprefix<prefix>]">

{{{ [.first[]] }}}

</$function>
  • No normally .first returns the first ‘tiddler’, the second redefine the first ‘shadow’.

PS Get some sleep :nerd_face:

However

It is interesting looking at the parse tree and reviewing the pragma function. As is often said functions are just variables, and in the “parse tree” you see the use of the “set widget?”.

Definition

[
    {
        "type": "set",
        "attributes": {
            "name": {
                "name": "name",
                "type": "string",
                "value": ".first"
            },
            "value": {
                "name": "value",
                "type": "string",
                "value": "[all[shadows]first[]addprefix<prefix>]"
            }
        },
        "children": [],
        "params": [
            {
                "name": "prefix",
                "default": "top - "
            }
        ],
        "orderedAttributes": [
            {
                "name": "name",
                "type": "string",
                "value": ".first"
            },
            {
                "name": "value",
                "type": "string",
                "value": "[all[shadows]first[]addprefix<prefix>]"
            }
        ],
        "isFunctionDefinition": true
    }
]

<<.first>>

[
    {
        "type": "transclude",
        "start": 2,
        "end": 12,
        "attributes": {
            "$variable": {
                "name": "$variable",
                "type": "string",
                "value": ".first"
            }
        },
        "orderedAttributes": [
            {
                "name": "$variable",
                "type": "string",
                "value": ".first"
            }
        ],
        "isBlock": true
    }
]

Ah, so here:

\function .sort(default:"title") [sort<title>]

You meant to say:


\function .sort(default:"title") [sort<default>]

Should have spotted that.

Anyway…

I don’t see how the <$function ...> syntax can easily/nicely assign params to attrs. That’s what the \function f(params) syntax is for.

I mean this…

<$function 
  .fn1=[stuff]         .fn1-param-1=X
  .fn2=[things]        .fn2-param-1=A .fn2-param-2=B
  .etc=[fiddlersticks] .etc-param-1=wtf
>

is uglier than a pigs breakfast.

In fact its interesting to compare the parse tree for;

\define my.macro() A macro
\procedure my.proc() A Procedure
\function my.function() A Function
  • First they are nested, to be expected given the operation of the set widget
  • A key difference in the definitions are;
    • “isMacroDefinition”: true
    • “isFunctionDefinition”: true
    • “isProcedureDefinition”: true

And the set widget.

Arguably we could have a parameter on the $set widget or a new widget that allows this to be set (but I am sure there is more to it).

Hi @TW_Tones my checklist for the parameterised transclusion PR includes one item that I didn’t get around to doing:

Extend set widget to set the hidden parse tree properties like isprocedure, and to be able to specify parameters

Part of the reason was that while it clearly plugs a logical hole, I wasn’t sure that there were very many practical use cases. The OP mentions redefining functions, but perhaps another interesting application would be the ability to define functions where the text of the function is computed.

1 Like

So @jeremyruston you had anticipated this?

So the idea would be to permit the set widget to define and redefine functions/procedures and macros by setting this indicator?

Yes, the ability to define the above in line would be very welcome, but also as you suggest being able to define them based on computed values. Even the name of the “functions/procedures and macros” may prove interesting.

What is a collective name for “functions/procedures and macros”?

I do think this enhancement would help in some cases where local redefinition is needed and do somethings that are currently impossible. However, it is clear it would open up opportunities in TiddlyWiki Script we can’t yet imagine. It allows more room for control over TiddlyWiki Script and recursive/self referential coding (with parameters/variables in re/definitions).