In the thick of programming, I often make bracket/double-bracket errors, such as
Tr[[matrix]] instead of Tr[matrix]
or
list[1] instead of list[[1]].
Unfortunately, in the former the error message
Part::pspec: Part specification A is neither an integer nor a list of integers.
doesn't uniquely specify and localize the problem in a long program, and in the latter no error message is generated at all. (If any Wolfram employees are reading this, please consider generating a more informative error message for Print[["hello"]]
that flags that Print
was bracketed as a list instead of a function.)
I couldn't think of a reason why Mathematica necessarily needs different kinds of brackets for functions and lists. The bracket/double-bracket convention lets you distinguish functions from lists by context, but it decreases readability of complicated expressions and makes me prone to coding mistakes. Note added: Albert Retey commented that if f
is defined as a pure function via f=Function[x,x^2]
(rather than as f[x_]=x^2
) then f[1]
and f[[1]]
are simultaneously defined and nonequal unless x=1
. This gave the example I hadn't thought possible and (to make matters worse) provided a bracket/double bracket hazard which won't generate even a cryptic error message.
In the case of functions, I partially solved the problem by manually applying the following function declaration to all native functions (except Function[ ]
itself) and to user-defined non-pure functions:
Attributes[DeclareFunction] = {HoldAll};
DeclareFunction::HeadInvalid = "The Argument `1` of DeclareFunction
must have a head other than Function.";
DeclareFunction[f_] :=
If[Head[f] === Function,
Message[DeclareFunction::HeadInvalid, f],
Block[{prot},
prot = MemberQ[Attributes[f], Protected];
Unprotect[f];
f::FunctionAsList = "Changed `1`[[ ]] to `1`[ ]";
f[[x__]] ^:= (Message[f::FunctionAsList, f]; f[x]);
If[prot, Protect[f]]]]
After DeclareFunction
is applied to a function f
, the offending double-brackets are automatically interpreted as single-brackets and a warning message is given, pointing out the function with the offending double-bracket: After
DeclareFunction[Print]
the command
Print[["Hello"]]
yields
Print::FunctionAsList: Changed Print[[ ]] to Print[ ] >>
Hello
However,
- Is there a way to write an analogous
DeclareList
command? OnceDeclareList[list]
is invoked,list[ ]
should be automatically converted tolist[[ ]]
with a warning message given. - It would also be nice to find an unobtrusive way to invoke
DeclareFunction
automatically any time a new function is defined using the usualf[x_]:=
method. A complication is that if I modify the functionSetDelayed[ ]
then I run into issues of the modification recursing on itself instantly as it is made.
Any ideas?
a[1]
,a[2]
, ....? Botha[1] = 42
anda[[1]] = 42
are valid and useful assignment expressions that mean very different things, and are an example of the why Mathematica has single and double bracket notation. $\endgroup$someList[[i]]
is just syntactic sugar forPart[someList, i]
$\endgroup$a
is an indexed variable or a function, you use[]
. Also, it is entirely possible to usePart[]
on "non-atomic heads" (see e.g. this), and it is possible to have a list as a head, e.g.Through[{Sin, Cos}[30 °]]
. $\endgroup$[]
vs.[[]]
makes a difference:f = Function[x, x^2]
. Tryf[1]
vs.f[[1]]
, both are valid operations but in this case return different results $\endgroup$