How can I programmatically detect side effects (compile time or runtime)?

I have an idea for caching that I am starting to implement:

Memoizing function and saving return along with the hash of the function signature in Velocity . Using PostSharp , I want to check the cache and return a rehydrated representation of the return value instead of calling the function again. I want to use attributes to control this behavior.

Unfortunately, this can be dangerous for other developers in my organization if they fall in love with performance gains and start decorating each method in sight with caching attributes, including side effects. I would like to issue a compiler warning when the memoization library suspects that a function may cause side effects.

How can I say that code can cause side effects using CodeDom or Reflection?

+1
source share
3 answers

This is an extremely difficult problem, both in practice and in theory. We think a lot about how to prevent or isolate side effects for your scenarios - memoization, automatic parallelization , etc. - but it is difficult, and we are still far from a workable solution for C #. So no promises. (Consider switching to Haskell if you really want to eliminate side effects.)

Unfortunately, even if a miracle happened and you found a way to prevent the recall of methods with side effects, you still have big problems. Consider the following:

1) What if you memoize a function that calls the memoized function itself? This is a good situation, right? You want to be able to create memoized functions. But memoization has a side effect: it adds data to the cache! So, right away you have a meta problem: you want to tame side effects, but only the β€œbad” side effects. The "good" that you want to promote, the bad that you want to prevent, and it's hard to tell them apart.

2) What are you going to do with exceptions? Can you memoize the method that throws the exception? If so, does it always raise the same exception, or does it throw a new exception each time? If first, how are you going to do this? If the latter, now you have a memoized function that has two different results in two different calls, because two different exceptions are thrown. Exceptions can be seen as a side effect; it’s hard to tame exceptions.

3) What are you going to do with methods that do not have a side effect, but nevertheless unclean methods? Suppose you have a GetCurrentTime () method. This has no side effect; The call has not been changed. But this is not a candidate for a memorandum, because any two calls are required to get different results. You do not need a side effect detector, you need a purity detector.

I think your best bet is to solve a human problem through education and code reviews, rather than trying to solve a complex technical problem.

+8
source

Simply put, you can neither with CodeDom nor with Reflection.

To determine exactly whether a method causes side effects, you must understand what action it takes. For .Net, this means that cracking opens the IL and interacts with it in some way.

Neither reflection nor CodeDom give you this opportunity.

  • CodeDom is a method of generating code in an application and has very limited validation capabilities. It is essentially limited to a subset of the language understood by a different parsing machine.
  • The power of reflections lies in the ability to validate metadata rather than the underlying IL of the method body. MetaData can provide you with a very limited set of information about what it does and does not cause side effects.
0
source

Reflection alone will not do this because metadata does not have such attributes.

CodeDom may not be powerful enough to validate all IL instructions.

Thus, you will need to use very low-level fragments of the reflection API, which will allow you to get a byte[] containing the source IL of each method and analyze this. So this is possible in principle, but not easy.

You will need to analyze all the instructions and see what effects they have, and whether these effects will survive outside of some significant area (for example, they change the fields of objects that can flow through return values ​​or out , or they just change the transition objects, which are guaranteed to be inaccessible outside the method?).

Sounds pretty complicated!

0
source

All Articles