The below code defines a couple "objects" in the Mathematica sense using a convention consisting of so-called Q-functions for creating types and data validation, MakeBoxes
for formatting, Association
's for data, and SubValues
for properties and methods. (It's a more of a convention than a framework and one I use often because it is not fussy and embraces Mathematica's symbolic paradigm.)
However, recently I have run into display issues of my custom formats within Dataset
. Whenever I have an object like SubObject
below it displays fine but when I have an on object like Object
below which itself can contain a list of SubObject
's, the displaying of even a list of such Object
objects results in ...
being displayed and notably this only seems to happen with an Object
object contains a list of more than one SubObject
objects.
Thank you ahead of time for any insights or fixes.
To test this out, plese just copy the below code and then run the subsequent tests to get the weird Dataset
display issues. Here's my code to define the objects:
(*Utility q-function defining allowed rule pattern.*)
ClearAll[validRuleQ];
validRuleQ[(Rule | RuleDelayed)[_String, _]] := True;
validRuleQ[__] := False;
(*SubObject Data Q-Function*)
ClearAll[SubObjectDataQ];
SubObjectDataQ[
Association["Name" -> _String,
"Date" -> _?DateObjectQ, ___?validRuleQ]] := True;
SubObjectDataQ[__] := False;
(*SubObject Q-Function*)
ClearAll[SubObjectQ];
SubObjectQ[SubObject[_?SubObjectDataQ]] := True;
SubObjectQ[__] := False;
(*SubObject*)
ClearAll[SubObject];
(*SubObject Format*)
SubObject /:
MakeBoxes[obj : SubObject[_?SubObjectDataQ], form : StandardForm] :=
FrameBox[
RowBox[{StyleBox[obj["Name"], Bold], " ",
StyleBox["(subobject)", Bold, Gray]}], RoundingRadius -> 5,
Background -> LightBlue];
(*SubObject Constructor*)
SubObject[name_String, date_?DateObjectQ, rules___?validRuleQ] :=
SubObject[Association["Name" -> name, "Date" -> date, rules]];
(*SubObject Properties*)
SubObject[assoc_?SubObjectDataQ]["Association"] := assoc;
SubObject[assoc_?SubObjectDataQ]["Properties"] := Keys[assoc];
SubObject[assoc_?SubObjectDataQ][key_String] := Lookup[assoc, key];
(*Object Data Q-Function*)
ClearAll[ObjectDataQ];
ObjectDataQ[
Association["Name" -> _String, "Date" -> _?DateObjectQ,
"Objects" -> {___?SubObjectQ}, ___?validRuleQ]] := True;
ObjectDataQ[__] := False;
(*Object Q-Function*)
ClearAll[ObjectQ];
ObjectQ[Object[_?ObjectDataQ]] := True;
ObjectQ[__] := False;
(*Object*)
ClearAll[Object];
(*Object Format*)
Object /:
MakeBoxes[obj : Object[_?ObjectDataQ], form : StandardForm] :=
FrameBox[RowBox[{StyleBox[obj["Name"], Bold], " ",
StyleBox["(object)", Bold, Gray]}], RoundingRadius -> 5,
Background -> LightBlue];
(*Object Constructor*)
Object[name_String, date_?DateObjectQ, objects : {___?SubObjectQ},
rules___?validRuleQ] :=
Object[Association["Name" -> name, "Date" -> date,
"Objects" -> objects, rules]];
(*Object Properties*)
Object[assoc_?ObjectDataQ]["Association"] := assoc;
Object[assoc_?ObjectDataQ]["Properties"] := Keys[assoc];
Object[assoc_?ObjectDataQ][key_String] := Lookup[assoc, key];
Here's the code to test the object definitions and see the output in a Dataset
.
First, create some SubObject
objects and their list variable with this code:
(*Create some SubObject objects and then put them in a list for later.*)
so1=SubObject["SubObject1",DateObject[]];
so2=SubObject["SubObject2",DateObject[]];
so3=SubObject["SubObject3",DateObject[]];
sobjs={so1,so2,so3}
This should display like this:
Now create the Object
objects and their list with this code:
(*Create some Object objects and then put them in a list for later.*)
o1=Object["Object1",DateObject[],sobjs[[1;;1]]];
o2=Object["Object2",DateObject[],sobjs[[1;;2]]];
o3=Object["Object3",DateObject[],sobjs[[1;;3]]];
objs={o1,o2,o3}
This should display like this:
Now, simply display the Dataset
for the SubObject
object list:
(*Display SubObject Dataset*)
Dataset[sobjs]
Which displays as expected like so:
Problem:
And finally, the unexpected problem is here where the ...
displays instead of an Object
object for any Object
objects that contain more than one SubObject
in a list, which in our case are the variables o2
and o3
. Here's the problematic code:
(*Problematic code for display of Object in Dataset*)
Dataset[objs]
Which displays as
How do I fix this so the Object
objects display in Dataset
correctly?
(Note: I have tried using HoldAll as an attribute on the constructor functions symbols, but this is not a desirable solution because then it's not convenient to script with the objects as any input variables to the constructors, such as a list of SubObject
s into the constructor for Object
won't be evaluated before insertion to the Association data.)