Take Erlang for example:
1> X = 1.
1
2> X = 2.
** exception error: no match of right hand side value 2
Notice variables are immutable (not just values themselves). Once X becomes 1, it can only match with 1 after that. You might think this is silly or annoying, why not just allow reassignment and instead have to sprinkle X1, X2 everywhere. But it turns out is can be nice because it makes state updates very explicit. In complicated applications that helps understand what is happening. And it behaves like you'd expect in math, in the sense that X = X + 1 doesn't make sense here either: 1> X = 1.
1
2> X = X + 1.
** exception error: no match of right hand side value 2
3>
It does pattern matching very well too, that is, it matches based on the shape of data: 1> {X,Y} = {1,2}.
{1,2}
2> X.
1
3> Y.
2
4>
In other languages we might say we have assignment and destructuring but here it is rather simple it's just pattern matching.