19

I'm learning about code contracts in .NET, and I'm trying to understand the idea of pure constructors. The code contracts documentation states:

All methods that are called within a contract must be pure; that is, they must not update any preexisting state. A pure method is allowed to modify objects that have been created after entry into the pure method.

And the PureAttribute documentation states:

Indicates that a type or method is pure, that is, it does not make any visible state changes.

I understand these statements when it comes to methods, but what about constructors? Suppose you had a class like this:

public class Foo
{
    public int Value { get; set; }

    public Foo(int value) {
        this.Value = value;
    }
}

This constructor obviously does affect the state of the new Foo object, but it has no other side effects (e.g. it doesn't manipulate any of the parameters or call any non-pure methods). Is this a candidate for [Pure] or not? What is the significance of placing a [Pure] attribute on a constructor, and when should I do this in my own code?

p.s.w.g
  • 4,135
  • 4
  • 28
  • 40

2 Answers2

16

You decorate a method with [Pure]:

  • If the method doesn't have side effects. For example, if the method accesses a database and modifies it or its result depends on the database, it's not pure.

  • And if you expect to use it in code contracts. For example, if the method is pure, but you have no intention to use it in code contracts, adding [Pure] would have no benefit and won't make your code faster.

As far as it concerns constructors, it looks like they are assumed to be pure in .NET and don't need an explicit attribute. I looked at several constructors in .NET Framework source, such as DateTime, and they don't have [Pure] attribute.

I suppose this is done for several reasons:

  • It may be too impractical to have to write a parameterless constructor with [Pure] attribute just to be able to use the class/struct in a contract.

  • Some, such as String, don't have explicit constructors.

  • The constructors receive special treatment even outside code contracts; for example, you're not expected to throw exceptions inside them.

  • [Pure] is just a convention which is here to simplify your life, but there is no actual static checking to ensure that the method decorated with this attribute is pure. void DestroyDatabase() may be decorated as being pure, and code contracts won't notice anything wrong.

    Currently there is no component of Code Contracts which checks if methods declared pure are pure indeed. Thus if a programmer decorated a method with [Pure], it’s just believed.

    From Code Contracts #5: Method purity

  • .NET Framework itself contains constructors which are not pure. For example, List<T>(IEnumerable<T> collection) is actually impure if looping through the collection has side effects.

  • Contracts shout be kept simple. I can easily imagine a contract such as Contract.Requires(!string.IsNullOrEmpty(name)), so there are good reasons to declare the static string.IsNullOrEmpty pure.

    On the other hand, if you need a StringBuilder in order to build the string you'll check then for something by calling an instance method of your business class, you're probably misusing the contracts. That's also why StringBuilder.ToString is not marked as pure, even if it might be (is it?)

Arseni Mourzenko
  • 134,780
  • 31
  • 343
  • 513
  • Many code contracts on system types are assumed by the contract checker, including "*any method whose fully qualified name begins with "System.Diagnostics.Contracts.Contract", "System.String", "System.IO.Path", or "System.Type"*". Unfortunately, I'm not sure if looking at the .NET types is too useful when it comes to code contracts. – p.s.w.g Jul 01 '14 at 16:59
  • 3
    Purity is one of those things where all called code also has to be pure, or the caller is not "pure". I find it difficult to believe all constructors are considered pure by default. – Frank Hileman Jul 01 '14 at 17:09
  • @FrankHileman: me too. I don't have a C# compiler right now, but it would be enough to write a class with a constructor and no `[Pure]` attribute, and use it somewhere else in a contract to have a definitive answer. – Arseni Mourzenko Jul 01 '14 at 17:14
  • I find the assertion that any constructor is pure baffling. Maybe I'm missing something, but the entire purpose of a constructor is to create a side-effect. Even a parameterless constructor isn't pure if the class has a single field or property. I'm perfectly willing to be proven wrong here, but if to succeed, you'll have to completely upend my understanding of determinism in programming. – Michael Meadows Apr 10 '23 at 18:27
1

The object cannot be used until it is constructed in this case. Therefore the constructor is pure. If the constructor called other code, or invoked a delegate, and the other code modified the mutable property, it would not be pure. To be safer, it is better to make the property immutable.

Frank Hileman
  • 3,922
  • 16
  • 18
  • So a pure constructor is a pure method which is allowed to change the state of the current class, as long as it satisfies the other conditions of being pure? BTW, The property is mutable because I wanted to emphasize that this class itself is not pure. – p.s.w.g Jul 01 '14 at 16:36
  • @p.s.w.g: You created an interesting question which probably has to be answered by Microsoft. Suppose the constructor invoked a method that modified the mutable property; would the constructor still be pure? I think technically it would not be, even though the modification is "invisible" to external viewers. Since there is no other code invoked in your original example, it must be pure by any definition I can think of. – Frank Hileman Jul 01 '14 at 17:07
  • @p.s.w.g: Except that the property set is also a method call.. I think you should ask on the MSDN forums. – Frank Hileman Jul 01 '14 at 17:11
  • I guess if the central idea of purity is whether or not the method makes any *observable* changes, then in that sense, regardless of whether or not it calls non-pure methods, as long as the changes can't be *observed* by any caller, it would still be a pure method. – p.s.w.g Jul 01 '14 at 18:55
  • @p.s.w.g: That is the abstract definition. But if I was writing an analyzer for these things, probably an non-pure method call would also be considered to make the caller non-pure. Just for simplicity of implementation. Then the question is, is a constructor a normal method call, or how deep does the analysis go. – Frank Hileman Jul 02 '14 at 02:54
  • Frank, something tells me if you were writing an analyzer that you wouldn't need the pure attribute... wouldn't you just look at the operands and determine it for yourself? the jit could definitely determine this in its own if it needed the sad part is that it's not... Pure is as pure does... – Jay Apr 05 '18 at 15:20
  • @Jay You are right. A different CLR and different languages would help. – Frank Hileman Apr 06 '18 at 16:58