Automatic Handling of bracket vs double-bracket errors

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_] :=
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,

1. Is there a way to write an analogous DeclareList command? Once DeclareList[list] is invoked, list[ ] should be automatically converted to list[[ ]] with a warning message given.
2. It would also be nice to find an unobtrusive way to invoke DeclareFunction automatically any time a new function is defined using the usual f[x_]:= method. A complication is that if I modify the function SetDelayed[ ] then I run into issues of the modification recursing on itself instantly as it is made.

Any ideas?

• Not an answer to your question, but you may find this useful: type ESC [[ ESC to get a special double-bracket character which is (in my opinion) much more readable. I always use this character. Since I find ESC [[ ESC too time consuming to type, I set up Ctrl-[ as a keyboard shortcut to type it more easily. – Szabolcs Dec 26 '16 at 9:30
• "I couldn't think of a reason why Mathematica necessarily needs different kinds of brackets for functions and lists." Have you never used indexed variables; i.e., a[1], a[2], ....? Both a[1] = 42 and a[[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. – m_goldberg Dec 26 '16 at 9:46
• Note that someList[[i]] is just syntactic sugar for Part[someList, i] – Sascha Dec 26 '16 at 9:49
• "I infer that Mathematica won't let me simultaneously use the variable a as a list and a function" - you infer right. If a is an indexed variable or a function, you use []. Also, it is entirely possible to use Part[] 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 °]]. – J. M. is away Dec 26 '16 at 10:19
• here is an example where [] vs. [[]] makes a difference: f = Function[x, x^2]. Try f[1] vs. f[[1]], both are valid operations but in this case return different results – Albert Retey Dec 26 '16 at 10:29

You can better distinguish between Part and other bracket syntax by using the shorthand LeftDoubleBracket, Esc [[ Esc , and shorthand RightDoubleBracket, Esc ]] Esc .
Now it is clear when Part is being called and when it is not. I always use LeftDoubleBracket and RightDoubleBracket to avoid the confusion you are experiencing.
• @user9490 No, it would not be useful. A simple example, N[Max[list]]. You would not want ]] converted in countless cases. For consistency of the in front end you explicitly use the shorthand for both double brackets. – Edmund Dec 26 '16 at 14:45