Wrapped Association into a “structure”: how to define Equal[] and what are the good practices for package dev?

Using a nice answer https://mathematica.stackexchange.com/a/197936/42847 I got from a previous question I define:

ClearAll[MyData]
SetAttributes[MyData, HoldFirst]
MyData[stuff : Except[_Symbol]] :=
With[{evaluatedStuff = stuff},
Module[{storeVar = evaluatedStuff}, MyData[storeVar]] /;
AssociationQ[evaluatedStuff]];


I understand that when stuff argument is an association, a local variable is created (thanks to Module[...]). This part is ok, demo:

MyData[<|"a" -> 1|>]


MyData[storeVar\$7548]

Now let's say I want to compare two such structures:

No problem here:

q = <|"a" -> 1|>
MyData[q]==MyData[q]


True

A problem I understand

MyData[<|"a" -> 1|>] == MyData[<|"a" -> 1|>]


MyData[storeVar$$7538] == MyData[storeVar$$7539]

Here we use two different internal variables to store stuff argument and they are not evaluated because of the HoldFirst attribute

So I introduce an overload for the Equal[] operator:

MyData /: Equal[A_MyData, B_MyData] := First[A] == First[B]


and now:

MyData[<|"a" -> 1|>] == MyData[<|"a" -> 1|>]


True

works as expected.

Problem with VerificationTest[]: now I want to do units tests:

VerificationTest[MyData[<|"a" -> 1|>], MyData[<|"a" -> 1|>]]


but I get an TestResultObject with Failure Outcome!!

First question: Why and how to fix that? (maybe my way to define Equal[] is not the right one?)

Second question:

More broadly speaking, when you write a MMA package using "structure" like MyData, what is the good practice when defining stuff like:

Format[MyData[a_Symbol?AssociationQ]] := "Pretty print of MyData[]"
MyData /: MyData[data_Symbol?AssociationQ][s_String] := data[[s]];


To put then in the public section or in the private one?

BeginPackage["FooPackage"];

MyData::usage="A structure ...";

... <- Format, Equal,... Here ?

Begin["Private"];

... <- Or here???

End[] (*Private *)

EndPackage[];

• Yes, it is not Equal: Options[VerificationTest, SameTest] – Kuba May 10 '19 at 10:53
• Thanks! I just realized that VerificationTest by default uses SameQ – Picaud Vincent May 10 '19 at 10:55

The reason your VerificationTest fails is because the default test for equality of expressions is SameQ, not Equals. Equals is for mathematical equality and does not always evaluate to a boolean while SameQ tests if expressions are literally the same:

ClearAll[x, y]
x == x


True

x == y


x == y

x === x


True

x === y


False

There are two things you can do:

1. Change the option of SameTest:

VerificationTest[MyData[<|"a" -> 1|>], MyData[<|"a" -> 1|>], SameTest -> Equal]

2. Add an UpValue for SameQ (this is probably the best option of the two):

MyData /: SameQ[A_MyData, B_MyData] := First[A] == First[B]; VerificationTest[MyData[<|"a" -> 1|>], MyData[<|"a" -> 1|>]]

As for your second question: I would say that all definitions should go in the Private` context, so that includes formatting rules. The part before the begin of the private section is mainly for creating the symbols you want to export from the package. This is usually done by defining the usage message for that symbol, but even that's not strictly necessary. Any mention of the symbol outside of the private context will create the symbol in the public context.

• Thanks again for this clear explanation (I just realized for the SameQ vs Equal). Ok for the second question – Picaud Vincent May 10 '19 at 10:58