expression cells versus program cells

The distinction between “expression cells” and “program cells” is an important one, since expression cells implicitly display their content and program cells do not. It can be surprising that for single line cells, the distinction can come down to whether or not they end in a semicolon.

For example:

1 + 2

This is an expression cell that will display ‘3’, whereas:

1 + 2;

This is a program cell and will display nothing.

Or, as another example:

md`This is markdown!`

This is an expression cell that will display ‘This is markdown!’, whereas:

md`This is markdown!`;

This is a program cell that will display nothing.

Or, one last example:

myFunction(myStuff)

This is an expression cell that will display ‘myOutput’, whereas:

myFunction(myStuff);

This is a program cell that will display nothing.

I think part of what can make this tricky is that there is no visual indication (other than the lack of output!) that the cell is being treated one way or the other, since the identification as “expression cell” or “program cell” is behind-the-scenes “magic” to the user. As a result, when you don’t get an output, it is easy to think that you have made an error somewhere in the code, and not realize the inclusion of the semicolon has switched it to a different type of cell.

This can be particularly confusing in cases like calling a function, where in “normal” Javascript you might be used to always ending the line with a semicolon. And in normal Javascript, ending a line with a semicolon or not generally has no functional meaning (except in rare circumstances related to syntax) and is generally considered just a “style” issue.

Perhaps there should be some (subtle?) visual indication of when a cell has been classified as “expression” vs “program”?

Agree!! This was a big breakthrough in my understanding of Observable. (And which helped my general JavaScript discipline…)

Insightful feedback @akrawitz, thank you!

Looking back, this behavior was inherited from Observable Framework, which was our first step back to vanilla JavaScript. I recall wanting a way to suppress the implicit display of fenced code blocks (Framework’s equivalent of cells), as Framework didn’t have a good way of doing that. In retrospect, using a hidden attribute in the info string would have been a more self-explanatory approach…

In Observable Notebooks, the hidden attribute is how we turn on and off the implicit display of cells. So I agree with your critique — given that we have the hidden attribute, I’m not sure we need the subtle distinction of a semicolon to control implicit display. We inherited the expression vs. program distinction from Framework because I’d gotten accustomed to it and didn’t think too much about it, but I can see it being confusing to newcomers.

I’d like to make this change as part of the upcoming work on automatic inspection of top-level variables. We should support automatic inspection if a cell contains only a single statement, too. (Though I don’t think we should display anything if there are multiple statements… JavaScript has a concept of a completion value, but it’s complicated to implement outside of eval and I don’t think it’s worth the trouble.)