to have x == y and yet find f(x) != f(y). This is because systems like Haskell do not verify that functions defined on types with user-defined equivalence relations be well-defined with respect to that equivalence. Thus the referential transparency is limited to types without equivalence relations. Extending referential transparency to user-defined equivalence relations can be done for example with a Martin-Lof identity type, but requires a dependently typed system such as in Agda, Coq or Idris. Contrast to imperative programming If the substitution of an expression with its value is valid only at a certain point in the execution of the program, then the expression is not referentially transparent. The definition and ordering of these sequence points are the theoretical foundation of imperative programming, and part of the semantics of an imperative programming language. However, because a referentially transparent expression can be evaluated at any time, it is not necessary to define sequence points nor any guarantee of the order of evaluation at all. Programming done without these considerations is called purely functional programming. One advantage of writing code in a referentially transparent style is that given an intelligent compiler, static code analysis is easier and better code-improving transformations are possible automatically. For example, when programming in C, there will be a performance penalty for including a call to an expensive function inside a loop, even if the function call could be moved outside of the loop without changing the results of the program. The programmer would be forced to perform manual code motion of the call, possibly at the expense of source code readability. However, if the compiler is able to determine that the function call is referentially transparent, it can perform this transformation automatically. The primary disadvantage of languages that enforce referential transparency is that they make the expression of operations that naturally fit a sequence-of-steps imperative programming style more awkward and less concise. Such languages often incorporate mechanisms to make these tasks easier while retaining the purely functional quality of the language, such as definite clause grammars and monads. Another example As an example, let's use two functions, one which is referentially transparent, and the other which is referentially opaque: int g = 0; int rt(int x) { return x + 1; } int ro(int x) { g++; return x + g; } The function rt is referentially transparent, which means that if x == y