Why is println considered an impure function?

Viewed 993

I'm reading the book programming in scala, and it is said :

... in this case , its side effect is printing to the standard output stream.

and I don't see where is the side effect, since, for the same input, println will print the same output (I think )
UPDATE
for example any time we call :

println(5)

it will print 5, I don't see a case where calling println(5) will print a value other than 5 !!

5 Answers

You can tell if an expression has a side effect by replacing the expression with its result. If the program changes meaning, there's a side effect. For example,

println(5)

is a different program to

()

That is, a side effect is any observable effect that isn't encoded in the result of evaluating an expression. Here the result is (), but there's nothing in that value that encodes the fact that 5 has now appeared somewhere on your screen.

The side effect is in the state of the computer. Each time you call println() the state of memory changes in order to display given value to the terminal. Or more generally, the state of the standard output stream is changed.

Consider the following analogy

var out: String = ""
def myprintln(s: String) = {
  out += s // this non-local mutation makes me impure
  ()
}

Here myprintln is impure because beside returning value () it also mutates non-local variable out as a side-effect. Now imagine out to be the stream vanilla println mutates.

Nice answers were already given to this question, but let me add my two cents.

If you will look inside println function essentially it is the same as java.lang.System.out.println() - so when you invoke Scala's standard library println method under the hood it invokes method println on PrintStream object instance which is declared as field out in System class (or more precisely outVar in Console object), which changes it internal state. This can be considered as another one explanation why println is impure function.

Hope this helps!

It has to do with the concept of referential transparency. An expression is referentially transparent if you can substitute it with its evaluated result without changing the program.

When an expression is not referentially transparent we say that it has side effects.

f(println("effect"), println("effect"))
// isn't really equivalent to!
val x = println("effect")
f(x, x)

while

import cats.effect.IO

def printlnIO(line: String): IO[Unit] = IO(println(line))

f(printlnIO("effect"), printlnIO("effect"))
// is equivalent to
val x = printlnIO("effect")
f(x, x)

You can find a more detailed explanation here: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html

Related