Well one can 'overload' system functions of Mathematica using UpValues for user-defined symbols like the abstract symbol array in the following:
ClearAll[array];
array/:Part[a_array,i_Integer]:=arrayGetPart[a,i]
array/:Part[a_array,ij_Span]:=arrayGetSpan[a,ij]
which for
array[{1, 2, 3}]
%[[1]]
%%[[1 ;; 2]]
results in calls to the currently undefined getters
array[{1, 2, 3}]
arrayGetPart[array[{1, 2, 3}], 1]
arrayGetSpan[array[{1, 2, 3}], 1 ;; 2]
The user-defined UpValues supersede the default behavior of Part on composite/user-defined objects, which can be disadvantageous in certain scenarios. The overloads or the getters should be further specified to avoid index out of range problems or implement stuff like [[-1]], missing implementations or interpretations for complicated Spans (e.g. m;;n;;l) or multi index versions of Part like [[All,1]]. I would suggest using very specific overloads (i_Integer/;0<i<LenghtOfArray[a]) or getters with rigorous checks on their input parameters to avoid bugs. Stuff like array/:Part[a_array, 0]:=array would also be a good idea to restore some of the default functionality of Part. After all the specific UpValues a plain UpValue like array/:Part[a_array, i_]:=... could be added either throwing some abort/error message or calling an undefined function to avoid undefined/unintended behavior.
Depending on what exactly OP intends to do, this approach might not be the best code solution in Mathematica but it is closed to the requested 'overloading' behavior. I have used similar constructs/'overloads' to construct data structures and wrappers in Mathematica. Following up on the comment of Jagra under OPs question I would also suggest using Association once the data object has an involved internal structure. Something along the lines array[<|"data"->{...}, "length"->n, "rowMajorQ"->True, ...|>] would come to mind. With this internal structure an overload like
ClearAll[array]
array /: Part[array[asoc_Association], i_] := Part[asoc["data"], i]
might be an attractive and highly flexible solution since the data stored in the Association can be extended and has named Keys. One caveat of the UpValue here would be the limitation of the access on the data-values only.
ClearAll[array]
array /: Part[array[asoc_Association], i_] := Part[asoc, i]
would be a more general approach allowing for things like array[<|...|>][["data"]][[1]] and also array[<|...|>][["rowMajorQ"]] which eliminates the need for all the trivial getters and is nice and verbose (given one uses good names for his keys).
b[n_] :=...? – Marius Ladegård Meyer Nov 23 '20 at 22:19TagSetor whatever it is called. That way, the definition is attached toBlahand not toPart. – Marius Ladegård Meyer Nov 23 '20 at 22:21Association[ ]. – Jagra Nov 23 '20 at 22:29Blahas a head andPartwill act onBlahthe same asPartdoes onList. For example, defineb = Blah["first", f[2], "third"];then evaluateb[[2]]. You getf[2], or whatever you put in the second position. When you evaluateHead @ b, you find thatbis aBlah. You can also defineb = Blah[ Null, f[2] ]. If you edit your question and include a bit more detail or specific examples of what it is you are trying to do, you will be more likely to get a useful answer. – LouisB Nov 24 '20 at 02:55Language`MutationHandlerfor more advanced custom "objects" – Lukas Lang Nov 24 '20 at 08:37