1

My workplace mostly uses C# for writing code. I'm trying to figure out a good way to indicate that a class with referentially transparent methods is intended to be referentially transparent (i.e., given the same set of arguments, you will always get the same return value) for future maintainers. I've considered just using static classes for classes that are intended to only contain referentially transparent methods but received pushback from my colleagues as they prefer an approach to unit testing where all classes depending on are stubbed out which they use constructor DI to accomplish. I don't see a disadvantage to not stubbing out referentially transparent functions for unit testing since they are almost always in-memory anyway but I've been unable to convince my colleagues of that.

Our class names use typical OO pattern names like DTO or Factory or Controllers and Models for namespaces. I'm not aware of any pattern names in OO that would indicate the sort of intent I am going for (i.e., to not introduce side-effecting operations or depending on things that read out of the db or filesystem).

jeff charles
  • 273
  • 1
  • 5
  • 1
    Start by holding a meeting with your colleagues to explain referential transparency. This won't actually work of course, nor will it communicate your intent, quite the opposite - you will learn from your colleagues that there is no chance of accomplishing this fruitless effort, resigned you will learn to keep your code as pure as can be regardless of your colleagues instead of in collaboration with them. – Jimmy Hoffa May 06 '14 at 15:51
  • 3
    `// This class only contains referentially-transparent methods.` – Robert Harvey May 06 '14 at 15:52
  • @RobertHarvey that comment's only useful if his intent is to get asked what referentially-transparent means more frequently – Jimmy Hoffa May 06 '14 at 15:54
  • 1
    And that comment has zero value after the new guy adds instance methods. – MetaFight May 06 '14 at 17:00
  • @MetaFight: You can't put instance methods in a `static` class. – Robert Harvey May 06 '14 at 17:03
  • @RobertHarvey you can by removing the `static` keyword. All the previously defined methods will remain static, but you'll be able to add instance methods. My point was that a comment won't stop someone sufficiently uninformed from unintentionally breaking your class. – MetaFight May 06 '14 at 18:12
  • 2
    @MetaFight: A big stick sometimes works wonders. – Robert Harvey May 06 '14 at 18:14

4 Answers4

5

Put a comment in the XML header of the class, to the effect of "This static class contains only referentially transparent methods, like those in the System.Math static class. Don't put functions which cause side-effects here."

Referentially-transparent methods are the easiest of all methods to test: hand them a value, and examine the return value. That's it.

Of course, the pushback is going to be "how do I know this 'referentially-transparent' method doesn't call other methods?" The answer to that is that you tested those other methods, and you already know they work, right?

Further Reading
Is static universally "evil" for unit testing and if so why does resharper recommend it?

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • This is the answer, because there is absolutely no way to determine if a method does anything stateful (as far as I know). This has to be enforced manually. Preferably, require code reviews for such classes. – Magus May 06 '14 at 18:25
3

The best way I can imagine to do this is to use a namespace named pure or stateless or referentially-transparent (which will likely just confuse most, so stick with a simpler name than referentially transparent). With this all you need to communicate to your colleagues is "Namespace X only contains referentially transparent code" so anytime someone uses that namespace they might get the click in their head of understanding.

Jimmy Hoffa
  • 16,039
  • 3
  • 69
  • 80
  • As you've already pointed out, this just begs the question. – Robert Harvey May 06 '14 at 15:56
  • 1
    @RobertHarvey only if you use the big scary term. A namespace with "stateless" in it might with a small meeting explaining to colleagues "Stateless namespace is only got pure stateless idempotent code" and that might be all it takes. I don't read comments, but I notice namespaces... – Jimmy Hoffa May 06 '14 at 15:58
  • Really that's kinda the whole point of a `static` class. – Robert Harvey May 06 '14 at 16:09
  • @RobertHarvey: Static classes can (and should!) be used that way, but they don't enforce statelessness. Ultimately, nothing you do can protect against stupidity and ineptitude. – Magus May 06 '14 at 18:15
  • I'm going to select this as the answer since I feel like the namespace will be more noticeable during code reviews than relying on someone to expand the diff and notice the XML header. @RobertHarvey: I think your answer has value too, I just think the namespace approach makes it easier to enforce. – jeff charles May 06 '14 at 18:52
  • Well, it will certainly give them pause if they have to type `using ReferentiallyTransparentMethods`, I suppose. I personally prefer that the namespace hint at the functionality gathered there rather than some code characteristic. – Robert Harvey May 06 '14 at 18:55
0

This is really jumping through hoops but what about creating a base class called ReferentiallyTransparentBase whose constructor throws an exception? Then when the person starts debugging the exception they'll see the comment // THIS CLASS'S METHODS WILL BREAK IF YOU CREATE INSTANCES OF IT. SO DON'T DO IT. Hopefully they'll get the picture.

Dunk
  • 5,059
  • 1
  • 20
  • 25
-1

I don't do much C# development but it seems to me you could define an attribute and apply it to all such classes. You could then give a thorough description of what restrictions that imposes on classes within the documentation of the attribute. That way your intent is still documented but you don't have to copy-and-paste some boilerplate about referential transparency into the documentation for all the classes.

Doval
  • 15,347
  • 3
  • 43
  • 58
  • What would you do in code with such an attribute? – Robert Harvey May 06 '14 at 15:55
  • Attributes are not documentation, this is a bad approach. Attributes are meant to have meaning in actual code, not semantic meaning for users – Jimmy Hoffa May 06 '14 at 15:56
  • @RobertHarvey Unless I'm misunderstanding, this is a documentation/specification issue - there's nothing to do "in code" with any kind of documentation. – Doval May 06 '14 at 15:57
  • 1
    The purpose of attributes is to eventually reflect over them and do something with them in code. That "something" could be in the form of generating documentation. – Robert Harvey May 06 '14 at 15:59
  • The issue with this is that attributes are not documentation, word docs and comments and things are documentation, attributes are actually recognized by the compiler at compile time and turned into IL attributes in the compiled image which your code can utilize in various ways. Attributes are code, not documentation. – Jimmy Hoffa May 06 '14 at 16:03
  • I was thinking along the lines of Java's annotations, e.g. @NotNull, which are used for documentation and static analysis rather than runtime. I guess with some work you could verify that any static classes that get imported have the ReferentiallyTransparent attribute? – Doval May 06 '14 at 16:09
  • The attribute still doesn't solve the problem. It can't guarantee anything. Someone could come along and add a stateful method. I personally don't think there *is* a right answer here other than a threatening comment. – Magus May 06 '14 at 18:19
  • @Magus I agree, there's really no way to enforce it, but the question was ways to communicate *intent*, not to enforce a correct implementation. An attribute with a well-documented and well-known meaning just seemed like a good way to avoid having a large slab of boilerplate regarding referential transparency in multiple files. I see that was a poor/unpopular choice though. – Doval May 06 '14 at 18:51
  • I think people are just unhappy that you're suggesting using compiler metadata to communicate with developers. I must admit I agree, though I don't quite find it downvote-worthy. – Magus May 06 '14 at 18:55