2
$\begingroup$

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,

  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?

$\endgroup$
18
  • 2
    $\begingroup$ 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. $\endgroup$
    – Szabolcs
    Dec 26, 2016 at 9:30
  • 1
    $\begingroup$ "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. $\endgroup$
    – m_goldberg
    Dec 26, 2016 at 9:46
  • 1
    $\begingroup$ Note that someList[[i]] is just syntactic sugar for Part[someList, i] $\endgroup$
    – Sascha
    Dec 26, 2016 at 9:49
  • 3
    $\begingroup$ "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 °]]. $\endgroup$ Dec 26, 2016 at 10:19
  • 2
    $\begingroup$ 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 $\endgroup$ Dec 26, 2016 at 10:29

1 Answer 1

3
$\begingroup$

Just noticed that @Szabolcs mentions this in the first OP comment.

You can better distinguish between Part and other bracket syntax by using the shorthand LeftDoubleBracket, Esc [[ Esc , and shorthand RightDoubleBracket, Esc ]] Esc .

Using the OP examples.

Mathematica graphics

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.

Hope this helps.

$\endgroup$
1
  • $\begingroup$ @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. $\endgroup$
    – Edmund
    Dec 26, 2016 at 14:45

Your Answer

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

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