2
$\begingroup$

Can we construct a function Iceberg,
which maps a given expression X to Iceberg[X]
satisfying 1. and 2. and 3. ?

1. From Iceberg[X],
it is not possible to inspect/extract a part of X with usual method.
It would be better if there is no part of Iceberg[X].
Applying Iceberg to X is like putting X into an iceberg.

ex) It is not difficult to extract 3rd part of {101,102,103,104,105},
from Hold[{101,102,103,104,105}].

    In[1]  Hold[{101,102,103,104,105}][[1]][[3]] 

    Out[1] 103

So Hold is not like Iceberg.

Likewise, for HoldComplete, Unevaluate, Defer, Inactivate, ... and combinations of these commands, similar method can extract any part of X.

So they are not like Iceberg.

2. From Iceberg[X], there is a unique way to comeback to X.

In[2]  Icemelt[Iceberg[{101,102,103,104,105}]]
Out[2]  {101,102,103,104,105}

No function other than 'Icemelt', can do it.

3. In fact there is a function satisfying 1. and 2. :
Iceberg = ToString
Icemelt = ToExpression

But I ask you to find another solution.

I believe ToString/ToExpression is the only solution.

$\endgroup$
13
  • 3
    $\begingroup$ "I believe ToString/ToExpression is the only solution." -- Also, Encrypt / Decrypt. $\endgroup$ Jun 11, 2021 at 8:41
  • 3
    $\begingroup$ also Compress/Uncompress? $\endgroup$
    – kglr
    Jun 11, 2021 at 8:51
  • 1
    $\begingroup$ 1. Strings are easier to reason with -- they are simple structures, familiar, present in many programing languages. 2. Because strings are simple their application is limiting. 3. It is not clear what is your end goal. If strings let you achieve it faster or easier then use strings. $\endgroup$ Jun 11, 2021 at 9:50
  • 1
    $\begingroup$ @b3m2a1's myObj[] function does what Iceberg[] is supposed to, and we can define Icemelt[myObj[data_]] := data to get #2. $\endgroup$
    – Michael E2
    Jun 11, 2021 at 18:21
  • 4
    $\begingroup$ Does this answer your question? Custom atomic expressions - modern tutorial $\endgroup$
    – Michael E2
    Jun 11, 2021 at 18:25

3 Answers 3

4
$\begingroup$
ClearAll@Iceberg;
expr : HoldPattern[Iceberg[x_]] /; ! AtomQ[Unevaluated[expr]] := 
 System`Private`SetNoEntry[Unevaluated[expr]];
Iceberg /: MakeBoxes[v_Iceberg?AtomQ, fmt_] := 
 InterpretationBox[
  RowBox[{"Iceberg", "[", "\[LeftAngleBracket]", "\[RightAngleBracket]", "]"}], v];
Icemelt[HoldPattern[Iceberg[x_]]] := x

Now you can do

Iceberg[{1,2,3}]

enter image description here

I believe it satisfies the other requirements

In[80]:= Iceberg[{101, 102, 103, 104, 105}][[1]][[3]]

During evaluation of In[80]:= Part::partd: Part specification Iceberg[\[LeftAngleBracket]\[RightAngleBracket]][[1]] is longer than depth of object.

During evaluation of In[80]:= Part::partw: Part 3 of Iceberg[\[LeftAngleBracket]\[RightAngleBracket]][[1]] does not exist.

Out[80]= Iceberg[{101, 102, 103, 104, 105}][[1]][[3]]

In[81]:= Icemelt[Iceberg[{101, 102, 103, 104, 105}]]

Out[81]= {101, 102, 103, 104, 105}
$\endgroup$
2
  • $\begingroup$ This doesn't guard you from pattern matching in general, so IceMelt is not unique: Replace[Iceberg[{1,2,3}],Verbatim[Iceberg][x_]:>x]. I'm looking for something similar, that also prevents anyone from looking at insides with pattern matching, but everything is still visible in InputForm. Like Graph, I don't understand how graph works, it is AtomQ, EntryQ, and without WXF type, but it prevents looking inside of it with every other means, without some BinarySerialize/BinaryDeserialize like hacks of course. $\endgroup$
    – swish
    Sep 16, 2022 at 20:59
  • $\begingroup$ @swish - I am not aware of any method to do what you want without implementing it in the kernel C code, like Graph. $\endgroup$
    – Jason B.
    Sep 16, 2022 at 22:13
2
$\begingroup$

Silly, but fun

X = {101, 102, 103, 104, 105};

img = Rasterize[X];

ToExpression[TextRecognize[img]] === X
(* True *)
$\endgroup$
1
  • $\begingroup$ This is, great :) I was thinking that it will be an interesting challenge to list or enumerate all possible ways to do the "icebergs" in WL. $\endgroup$ Jun 11, 2021 at 19:14
0
$\begingroup$

So this seems to come close to satisfying all the properties, including Icemelt uniqueness. I don't know any method to hack this Iceberg at this point, but I'll think about it more. If someone knows a hack please let me know:

(* hold attribute helpers *)

HoldPosition[sym_Symbol[args___]] := With[{attrs = Attributes[sym], len = Length @ Unevaluated @ {args}},
    Which[
        MemberQ[attrs, HoldFirst],
        {1},
        MemberQ[attrs, HoldRest],
        Range[2, len],
        MemberQ[attrs, HoldAll | HoldAllComplete],
        Range @ len,
        True,
        {}
    ]
]

HoldPosition[_] := Missing["Position"]

HoldPositionQ[expr_, i_] := With[{pos = HoldPosition[Unevaluated[expr]]}, MissingQ[pos] || MemberQ[pos, i]]

SequenceHoldQ[sym_Symbol[___]] := MemberQ[Attributes[sym], SequenceHold]
SequenceHoldQ[_] := False


(* Icemelt *)

(* always melt with StackComplete  *)
Icemelt[Verbatim[Iceberg][data_]] /; MemberQ[Stack[], StackComplete] := data
Icemelt[iceberg_Iceberg] := StackComplete[Icemelt[iceberg]]
Icemelt[expr___] := $Failed


(* Iceberg *)

Iceberg::unbrk = "is unbreakable with ``";
Iceberg::symbol = "attempt at reading iceberg symbol is detected";

(* run this if anything except Icemelt is executed with Iceberg in it *)
Iceberg /: expr : (f : Except[Icemelt])[left___, iceberg_Iceberg, right___] /; ! SequenceHoldQ[Unevaluated[expr]] :=
With[{
    i = Length[HoldComplete[left]] + 1
},
    (
        Message[Iceberg::unbrk, HoldForm[DisableFormatting[f[left, Iceberg["\[Ellipsis]"], right]]]];
        $Failed
    ) /; ! HoldPositionQ[Unevaluated[expr], i]
]

(* formatting *)
Iceberg /: MakeBoxes[iceberg_Iceberg, fmt___] := With[{data = StackComplete @ Icemelt[iceberg]},
    BoxForm`ArrangeSummaryBox["Iceberg", "Iceberg"["\[Ellipsis]"], Style["🧊", 48], {{}}, {{data}}, fmt]
]

(* make Iceberg atomic *)
Iceberg /: iceberg_Iceberg /; System`Private`HoldEntryQ[iceberg] := System`Private`HoldSetNoEntry[iceberg]

(* make an Iceberg with protected symbol that only returns its data inside Icemelt *)
iceberg : Iceberg[data_] /; System`Private`HoldNotValidQ[iceberg] := Module[{var},
    var := If[MemberQ[Stack[], Icemelt], data, Message[Iceberg::"symbol"]; $Failed];
    SetAttributes[var, {Protected, ReadProtected, Locked}];
    System`Private`HoldSetValid[Iceberg[var]]
]

(* protect and lock it *)
SetAttributes[Iceberg, {ReadProtected, Protected, Locked, HoldAllComplete}]

Here is notebook with an example: https://www.wolframcloud.com/obj/nikm/Published/Iceberg.nb

$\endgroup$
3
  • $\begingroup$ This seems interesting as an academic exercise only. You can't even put your object inside a list without it complaining: {Iceberg[{1, 2, 3}], Iceberg[{1, 2, 3}]}. I think you would have a hard time doing anything useful with it $\endgroup$
    – Jason B.
    Sep 17, 2022 at 10:20
  • $\begingroup$ @JasonB. That's perfectly ok, it's intended to be held. You gotta support your iceberg by holding it at all costs :) $\endgroup$
    – swish
    Sep 17, 2022 at 13:23
  • $\begingroup$ @JasonB. Also a relaxation can be made with an additional condition ValueQ[Unevaluated[expr]] that will allow pure structural modification like wrapping lists and other symbols around icebergs. $\endgroup$
    – swish
    Sep 17, 2022 at 13:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.