EDIT: An envisioned answer to this post should be in the form of a mathematica code that can demonstrate how the internal checks discussed below can be bypassed. Everything goes... On my part, I think the system should be relatively safe, but I would like to be sure. See it as a challenge.
I know that this question has been asked many times. This is my take at it. Ideas are not mine, they are borrowed from many posts on this site. Below is the core of the best setup that I came up with (that I think will work for me). I designed it to be very robust and lightweight.
I've spent quite some time testing different possibilities. I realized that the issue was how to design a system that flows well with Mathematica and at the end it was all about evaluation control, the standard, versus non-standard (i.e. the use versus an assignment), and an interplay between general and specific definitions. I departed from the
OBJ[id_]@f1 := f1[id] design by keeping the
OBJ and the field
f1 tightly together. The challenge was to control the evaluation and detect incorrect use (more below).
The question is whether the setup is indeed robust/safe. I would encourage everyone to find a way to abuse the system below. This will help me get an idea of how robust/safe the system is.
AN ADS SYSTEM BEGIN:
objectExistsQ[___] := False; registerObject[___] := Print["cannot register object: invalid id structure."] registerObject[id_] := (objectExistsQ[id] = True); isFieldQ[___] := False; neo = "attempt to use non-existing object"; nef = "use of non-existing field"; nif = "attempt to use non-initialized field"; OBJ[id_] := Print[neo] /; ! objectExistsQ[id]; OBJ /: HoldPattern[_[___, OBJ[id_]@fm_, ___]] := Print[nef] /; ! isFieldQ[fm]; Protect[f1]; isFieldQ[f1] = True; HoldPattern[OBJ[id_]@f1] := Print[nif];
AN ADS SYSTEM END:
Assume that the code above cannot be changed. Is it possible to bypass all the checks while using it (i.e. while constructing expressions that involve
OBJ[id]@f1)? (NOTE: naturally, the print statements are to be implemented as interrupts.)
EDIT: Imagine that there is a package that, once invoked, prepares the definitions above and seals definitions of OBJ etc. Alternativelly, OBJ is defined in the Private scope of the package and cannot be directly accessed.
The specifications are like this:
obj not initialized, has to fail already on object
OBJ[$1]@f1 (* attempt to use non-existing object *)
and even if non-existing field is used
OBJ[$1]@f4 (* attempt to use non-existing object *)
when the object is initialized it has to fail on non-initialized field
registerObject[$2]; OBJ[$2]@f1 (* attempt to use non-initialized field *)
if the field does not exist it has to say that
OBJ[$2]@f4 (* use of non-existing field *)
assignment on non-existing object has to fail
OBJ[$3]@f1 = 1 (* attempt to use non-existing object *)
ibid if used on non existing field
OBJ[$3]@f4 = 1 (* use of non-existing field *)
assignment on registered (created) object has to work
registerObject[$4] OBJ[$4]@f1 = 1
but fail if the field does not exist
OBJ[$4]@f4 = 1 (* use of non-existing field *)
Is it possible to construct a piece of Mathematica code ...
OBJ[id]@f1... so that, e.g., the following erroneous assignment is being made
registerObject[$1]; ... OBJ[$1]@f2 = 3 ...
Note that in the code above a non-existing field is being used.
EDIT 2: More specifically, I am working on a phraser that will
(1) prepare the THE ADS system described in the beginning of the post
(2) convert "source" code, for example,
THIS@instanceMethod[args_]:= ( ... THIS@f1 = 1; THIS@f2 = THIS@f1 + args; ... )
OBJ[id_]@instanceMethod[args_] := ( ... OBJ[id]@f1 = 1; OBJ[id]@f2 = OBJ[id]@f1 + args; ... )
I am asking, very, very specifically: is the design I have present good from the safety of use point of view? Is it possible to find an example of the source code which will "cheat" all the safety rules implemented into the ADS system? For example, I worry that one might use AppendTo or simmilar constructs to perform wrong initializations. For example, the outcome of AppendTo[OBJ@f4, value], depends on how AppendTo internally behaves (e.g. if it holds the first argument or not, how it behaves when it encounters a non-initialized List as the first argument etc). Of course, one can try the command and see, but I cannot possibly try all such commands. I would like to form a general opinion, thus the question.