10

Is there a function or a macro where I can do the following:

(has-side-effects?  my-function  my-function-args)

: or something like it which can return true or false, or {:side-effects true/false, :result return_value)

I just need an easy way to test to see which functions are side effect free.

yazz.com
  • 57,320
  • 66
  • 234
  • 385

3 Answers3

7

If it is one of your functions add some metadata to mark if it has side effects.

Then you can check it with ((meta f) :side-effects)

If it is a third party function there is no way that I know of (other that changing their code to use the solution described above).

Actually, there is even then but it isn't pretty. You can wrap the function with your own, which has metadata.

Also, keep in mind that a pure function has one additional property besides not having side effects. Its evaluation depends only on its parameters, and not some global shared state, like an external variable or system time. You might want to add this to your metadata, too. Then you can check if it is really pure by checking for both metadata entries.

However, be warned:

This simply wouldn't work for functions that take other functions as parameters. Here's an example: Does calling map have side effects?

It doesn't here: (map inc [1 2 3])

But it does here: (map println [1 2 3])

Because the passed function may or may not have side effects.

Goran Jovic
  • 9,418
  • 3
  • 43
  • 75
  • Isn't it possible to check whether a ref has been accessed, or IO has taken place automatically? Wouldn't this mean that a side effect has occurred? – yazz.com Jan 02 '11 at 18:58
  • @Zubair: You can't list all possible side effect causes. I mean, what about calls to Java methods. – Goran Jovic Jan 02 '11 at 19:24
7

This isn't possible in the general case (unless you also manage to solve the halting problem.... :-) )

However, there are various techniques that you might consider using in specific circumstances:

  • Create a "whitelist" of functions that you know to be side effect free - e.g. most of the core Clojure APIs are side effect free
  • Use metadata to tag your own functions as suggested by Goran
  • Use annotations on Java classes / functions that you control
  • Use watches on Clojure references (with add-watch) if you want to check for side effects on specific Clojure references
mikera
  • 105,238
  • 25
  • 256
  • 415
5

Clojure is not a purely functional language. It does not force the purity on the functions using the type system like Haskell does. So, no, there is no (straightforward) way to know if a function is side-effect free or not in Clojure.

Abhinav Sarkar
  • 23,534
  • 11
  • 81
  • 97
  • 2
    I feel your answer is misleading. Your basis is that Clojure is not purely functional and does not force purity on functions. Yet it seems likely that you can create a function or macro in Clojure that can answer with "no side-effects can occur" or "side-effects possible." A solution that, in practice, may be useful. – Psyllo Aug 01 '11 at 21:20
  • @psyllo. I didn't know that you can create a function or macro in Clojure that guarantee "no side-effects can occur". Can you send me the command to do this? – yazz.com Aug 16 '11 at 17:23
  • @Zubair. Sure. The command to do this is simply to write functions in which no side-effects are possible. Use only side-effect free functions. – Psyllo Aug 16 '11 at 22:35