# How to build a TemplateBox with dynamic length GridBox?

I have created the following TemplateBox Rule.

MakeBoxes[ActuarialSurvivalProbability[x_,t_],StandardForm]:=TemplateBox[{
MakeBoxes[#,StandardForm]&/@x,
MakeBoxes[t,StandardForm]
},
"ActuarialSurvivalProbability",
DisplayFunction:>(RowBox[{
SubscriptBox[
"",
TagBox[GridBox[{{#2}},GridBoxDividers->{}],"Grid"]
],
SubscriptBox[
"p",
RowBox[{
"",
TagBox[GridBox[{#1},GridBoxDividers->{
"ColumnsIndexed"->{},
"RowsIndexed"->{1->Thickness[1]}
}],"Grid"]
}]
]
}]&),
Tooltip->"probability that atleast one of live(s) aged "<>ToString[x]<>" survives for "<>ToString[t]<>" year(s)"
]


Then I evaluate the following.

ActuarialSurvivalProbability[{x, y, z}, t]


I expect an answer like that generated from the following command:

RawBoxes@TemplateBox[{
MakeBoxes[#,StandardForm]&/@{"x","y","z"},
MakeBoxes[t,StandardForm]
},
"ActuarialSurvivalProbability",
DisplayFunction:>(RowBox[{
SubscriptBox[
"",
TagBox[GridBox[{{#2}},GridBoxDividers->{}],"Grid"]
],
SubscriptBox[
"p",
RowBox[{
"",
TagBox[GridBox[{{"x","y","z"}},GridBoxDividers->{
"ColumnsIndexed"->{},
"RowsIndexed"->{1->Thickness[1]}
}],"Grid"]
}]
]
}]&),
Tooltip->"probability that atleast one of live(s) aged "<>ToString[{"x","y","z"}]<>" survives for "<>ToString[t]<>" year(s)"
]


But instead the dynamic length of input fed to GridBox in DisplayFunction in {#1} as {"x","y","z"} is not formatting correctly.

Thanks to jkuczm for an idea: https://mathematica.stackexchange.com/a/159407/5478:

MakeBoxes[ActuarialSurvivalProbability[x_, t_], StandardForm] :=
With[{row = Table[Slot[i], {i, 2, Length[x] + 1}]} (*Key point,
row of slots generated*),
TemplateBox[
Prepend[MakeBoxes /@ Unevaluated@x,
MakeBoxes[t]] ,
"ActuarialSurvivalProbability",
InterpretationFunction -> (RowBox[{"ActuarialSurvivalProbability",
"[", RowBox[{RowBox[{"{", RowBox[Riffle[{##2}, ","]], "}"}],
",", #}], "]"}] &),
DisplayFunction :> (RowBox[{SubscriptBox["",
TagBox[GridBox[{{#}}, GridBoxDividers -> {}], "Grid"]],
SubscriptBox["p",
RowBox[{"",
TagBox[GridBox[{row},
GridBoxDividers -> {"ColumnsIndexed" -> {},
"RowsIndexed" -> {1 -> Thickness[1]}}], "Grid"]}]]}] &),

Tooltip ->
"probability that atleast one of live(s) aged " <> ToString[x] <>
" survives for " <> ToString[t] <> " year(s)"]]


• Thank you! you can also add a lastSlot variable like lastSlot=Slot[Length@x+1] inside With to fix the variable t in the formatting. But there is one problem if you copy this notation and evaluate it, it gives ActuarialSurvivalProbability[x, y, z, t] instead of the original ActuarialSurvivalProbability[{x, y, z}, t]. Is there a way to fix this? – user13892 Dec 10 '18 at 11:54
• @user13892 right, take a look now – Kuba Dec 10 '18 at 12:08
• Thanks you it works now. – user13892 Dec 10 '18 at 13:18
• Thank you @Kuba for the excellent answer. I would like to ask why the DisplayFunction is using RuleDelayed rather than just a Rule is it necessary? because i see the documentation using it as well. – user13892 Dec 10 '18 at 14:41
• @user13892 I am not 100% but I don't think it is necessary because Function or whatever you put there should not evaluate unless arguments are applied anyway. Otoh it is usually to follow docs because the fact that it does not matter does not imply it is implemented for Rule too :) – Kuba Dec 10 '18 at 14:51

You can use TemplateSlotSequence for variable length TemplateBox arguments:

MakeBoxes[ActuarialSurvivalProbability[x_, t_], StandardForm] := TemplateBox[
Prepend[MakeBoxes[t]] @ BoxFormListMakeBoxes[x, StandardForm],
"ActuarialSurvivalProbability",
InterpretationFunction -> (
RowBox[{
"ActuarialSurvivalProbability",
"[",
RowBox[{
RowBox[{"{", RowBox[{TemplateSlotSequence[2, ","]}], "}"}],
",",
#1
}],
"]"
}]&
),
DisplayFunction -> (
RowBox[{
SubscriptBox["", #1],
SubscriptBox[
"p",
RowBox[{
"",
GridBox[
{{TemplateSlotSequence[2]}},
GridBoxDividers->{"RowsIndexed"->{1->Thickness[1]}}
]
}]
]
}]&
),
Tooltip->"probability that at least one of live(s) aged "<>ToString[x]<>
" survives for "<>ToString[t]<>" year(s)"
]


Then:

ActuarialSurvivalProbability[{x, y, z}, t]


The advantage of using a TemplateSlotSequence solution is that the DisplayFunction/InterpretationFunction can be defined in a stylesheet.

A brief comment on TemplateSlotSequence

I think since the pure functions used in DisplayFunction and InterpretationFunction do not evaluate in the Wolfram Language kernel, TemplateSlotSequence was introduced as a way to enhance the creation of box structures. When the front end constructs the box expression using the DisplayFunction/InterpretationFunction, TemplateSlotSequence objects are interpreted as:

TemplateSlotSequence[1] -> Sequence[#1, #2, ...]
TemplateSlotSequence[2, ","] -> Sequence[#2, ",", #3, ",", ...]
TemplateSlotSequence[{3, 5}, " "] -> Sequence[#3, " ", #4, " ", #5]


Note that the above is not documented, and as with all undocumented functionality, it is subject to change.

• Any explanation why does it work? At the end those are *Functions not Templates. – Kuba May 7 '19 at 6:48
• @Kuba Both answers are nice and works. (I came to similar solutions for variable index tensor notation.) However, suppose I want to add extra argument after I copied the Displayed form structure into a new notebook cell. Neither of the proposed solutions nor my solution allows to to this. Is it possible to extend code which would allow extra editing in the copied Display structure? – user18792 May 7 '19 at 7:08
• @user18792 you can add Editable -> True to the TemplateBox`. – Kuba May 7 '19 at 7:10
• @user18792 As far as I know, it is not possible to increase the number of template arguments through normal editing. If you use Show Expression, then of course it is possible to change the number of template arguments. – Carl Woll May 7 '19 at 7:37
• @Kuba It does not add extra argument to the argument list. It multiplies one of arguments by a new symbol. – user18792 May 7 '19 at 7:39