19
$\begingroup$

Whether for nested Ifs or within scoping constructs like Module and Block, I never know whether to end the final expression with a semicolon. I know the semicolon suppresses output, but, for example, in a series of nested Ifs, one needs only to semicolon the outermost If to suppress output.

So, is it better practice to semicolon everything unless output is needed? Or is it better to semicolon nothing until the last point where output is unwanted?

$\endgroup$
8
  • 2
    $\begingroup$ I tend to put it everywhere I don't expect desired output: saves me from the "where'd that Null come from" and the "surprise multiplications" problems... $\endgroup$ Commented Jan 25, 2014 at 7:13
  • $\begingroup$ This clearly depends on the expression. For example, you can't just write If[x < 1, y = 1 z = 3 , y = 4 ] without a ; between y=1 and z=3. Even if you have the z=3 in a new line in the notebook. One still needs a ; $\endgroup$ Commented Jan 25, 2014 at 7:28
  • 1
    $\begingroup$ @Nasser - That's why I said the "final" expression—I mean the last expression before exiting a bracket. $\endgroup$ Commented Jan 25, 2014 at 7:39
  • 3
    $\begingroup$ You might find this answer helpful. $\endgroup$ Commented Jan 25, 2014 at 14:18
  • $\begingroup$ @m_goldberg I forgot about that answer! Do you think this should be closed as a duplicate? $\endgroup$ Commented Jan 25, 2014 at 18:23

1 Answer 1

27
$\begingroup$

I may be missing the point of this question, but I think it is important to note that ; is the short form of CompoundExpression, and it is not primarily for suppressing output.

You can see how ; is interpreted using one of the methods I described here:

HoldForm @ FullForm[a; b; c] HoldForm @ FullForm[a; b;] 
CompoundExpression[a, b, c] CompoundExpression[a, b, Null] 

Note that when a final expression is omitted Null is inserted, just like this behavior with ,:

{1, 2,} 
{1, 2, Null} 

The suppression of output is not a behavior of CompoundExpression but rather Null, which when returned as output (alone) is not printed. For example 2 Null/2 evaluates to Null, therefore when given as input no output is printed.

There is little point in sprinkling ; around your code without need, unless perhaps as a visual reminder that the evaluated form of a given expression is not directly used by the surrounding head. One exception is when writing code that will eventually be made into a function or Module as line breaks are not valid separators in this case, therefore even functions that already return Null such as SetDelayed should be terminated with a ;, e.g.:

foo[bar_Integer] := bar^2; foo[bar_Real] := bar/2; 

This avoids the error seen with:

Module[{foo}, foo[bar_Integer] := bar^2 foo[bar_Real] := bar/2 ] 

What ; is really for

The actual function of CompoundExpression is described in the documentation:

expr1;expr2; ... evaluates the expri in turn, giving the last one as the result.

CompoundExpression, while more succinct and canonical than other methods, is not the only way to accomplish this. For example you could use

Last[{expr1, expr2, ...}]
in the same manner, e.g.:

a = 5; b = a^2; Binomial[b, a] Last[{a = 5, b = a^2, Binomial[b, a]}] 
53130 53130 

And suppression of output:

x = Range@500; Last[{x = Range@500,}] (* no output printed *) 

You can also return a specific expression using Slot in a simple Function:

#2 &[a = 5, b = a^2, Binomial[b, a]] 
25 

This is specifically appropriate when you need to perform some action after generating an expression, such as closing a stream:

str = StringToStream["abcdefg 123456"]; # &[Read[str, Word], Close @ str] 
"abcdefg" 

I would be remiss not to mention that these alternative methods are not actually equivalent to CompoundExpression because even though they only return one expression (possibly Null) they still accumulate all of them in memory. Compare these, each pair of lines run in a fresh Kernel:

Range@1*^7; Range@1*^7; Range@1*^7; Range@1*^7; MaxMemoryUsed[] 
94923152 
Last[{Range@1*^7, Range@1*^7, Range@1*^7, Range@1*^7,}] MaxMemoryUsed[] 
174925336 

To get the memory performance of ; one would need something more complex, such as:

SetAttributes[ce, HoldAll] ce[x__] := Fold[#2 &, , Hold @ x] ce[Range@1*^7, Range@1*^7, Range@1*^7, Range@1*^7,] MaxMemoryUsed[] 
93506816 

Additional reading:

$\endgroup$
6
  • 3
    $\begingroup$ So when are you going to write that Mathematica book. I would love to read it :) $\endgroup$ Commented Jan 25, 2014 at 18:49
  • 4
    $\begingroup$ @RunnyKine "I've been studying the mystery of Mathematica for years; someday I'll publish my book: A Century of Studying Mathematica by Mr.Wizard, volume one The Early Years." :^) $\endgroup$ Commented Jan 25, 2014 at 19:07
  • $\begingroup$ Please, I'm curious to see the evolution of this amazing tool from someone who has studied it well before it became available :) $\endgroup$ Commented Jan 25, 2014 at 19:09
  • $\begingroup$ @RunnyKine In case you didn't get the reference: imdb.com/title/tt0088323 -- worth a viewing, even as an adult. (And my point was: when I've been using Mathematica that long I may finally be qualified to write a book about it.) $\endgroup$ Commented Jan 25, 2014 at 19:20
  • $\begingroup$ I've seen it a few times when I was much younger :). In any case, I'm pretty sure you're more than qualified to write one. $\endgroup$ Commented Jan 25, 2014 at 19:27

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.