Actually, they are, and they aren't. Mostly, they aren't, and that is the point of this post. Expressions are very powerful tools, and they can be used to great effect, especially when something needs a quick turn-around. One must take care, however, to construct expressions without pitfalls.
The basic rule of an expression is, don't call MEL functions to edit attribute values. This is not to say you can't, but it is to say that you shouldn't. There are some good reasons to avoid them. Let's look at one case.
In Maya, create a locator, 'locator1'. Select the translateX parameter in the Channel Box. From the context menu, select 'Expressions'. In the Expression Editor, set the following:
setAttr locator1.tx 1;
Press the 'Create' button. You will see locator1's translateX parameter set to one. What else do you notice?
The observant among you will notice that the locator's translateX channel does not turn purple, and if you have ever set an expression, you should know that the channel turns purple when an expression controls it. If you select the locator1 translateY and create this expression:
locator1.ty = 1;
you will notice the translateY channel turns purple.
Why is this important? Well, MEL commands like setAttr bypass Maya's Dependency Graph evaluation. Maya keeps track of the relationships between nodes by tracking the connections between node attributes. In this case, Maya knows that locator1.ty is 'connected' to something, even though the connection is implicit in the expression. If you look at locator1 in the Connection Editor, you will see that Maya recognizes the connection - this is a good thing.
So, MEL commands bypass the Dependency Graph, and this can cause no end of problems. By setting attrs in an expression, it can be difficult for Maya or another human to figure out where the heck a value is getting changed. It can also lead to undefined behavior within playback or rendering.
So what works well within an expression? To answer that, I will illustrate with two expressions - one 'wrong' one, and one 'right' one. Both of these expressions will do the same thing: given input attributes locator1.ty and locator2.ty, it will set locator3.ty to the distance between the first two attributes.
First, the wrong one:
float $ty1 = `getAttr locator1.ty`;
float $ty2 = `getAttr locator2.ty`;
float $result = pow(pow($ty1, 2) + pow($ty2, 2), .5);
setAttr locator3.ty $result;
I used some variables to keep it readable. If you create this expression on locator3, you will notice that it will not work unless the time slider is updated. Also, in the Connection Editor, you will see that the connection information is not obvious or complete.
Here is the 'right' one:
locator3.translateY = pow(pow(locator1.translateY, 2) + pow(locator2.translateY, 2), .5)
If you replace the previous expression with this one, you will notice that manipulating the locators forces an immediate update. You will also notice that the Connection Editor displays more complete and descriptive connection info.
So, should you never, ever, ever use MEL commands in expressions? Yes. Well, actually, it is tricky. As you can see, the 'right' expression used the math command 'pow' - and that's MEL. What you will notice, though, is that the attribute assignment mechanism is used - instead of variables, try to use the node.attribute syntax and assign values with '='.
There will be some times when you have no choice but to write MEL-heavy expressions. I had to do this for some dynamics simulations due to some bugs in Maya's particle system. But they should always be a last resort. Don't take the easy way out - use the expression engine to your best advantage.