Question

This question is followup to this question.

Is there any benefit in avoiding the 'this' operator when implementing pure methods? That is, are there any advantages to making all dependencies explicit via argument lists, versus allowing implicit dependencies by referencing instance data via the 'this' operator within the bodies of pure methods (doing so seems so funky to me). I have code examples of each case to help illustrate my question.

The following code example implements Narrate() as an instance method in which it's dependency is referenced via the 'this' operator within the body of the method. The Main() method provides how this class is used within client code (take note of how output is written):

public sealed class Version01_MutableLocation
{
    public string Name { get; set; }
    public string Description { get; set; }
    public Version01_MutableLocation North { get; set; }
    public Version01_MutableLocation South { get; set; }
    public Version01_MutableLocation East { get; set; }
    public Version01_MutableLocation West { get; set; }

    /// <summary>
    /// This instance method is a pure function, but it's dependency - the class instance - is referenced via the 'this' operator
    /// </summary>
    public string Narrate()
    {
        string narration = string.Empty;

        { // This block constructs the string that is the description
          // of the location that is displayed onscreen to the game player.
            string northExit =
                null != this.North ? " North" : string.Empty;

            string southExit =
                null != this.South ? " South" : string.Empty;

            string eastExit =
                null != this.East ? " East" : string.Empty;

            string westExit =
                null != this.West ? " West" : string.Empty;

            string allExits =
                string.Empty != string.Concat(northExit, southExit, eastExit, westExit)
                ? $"{Environment.NewLine}Exits:{northExit}{southExit}{eastExit}{westExit}"
                : string.Empty;

            string separator = new string('-', this.Name.Length);

            narration =
                $"{this.Name}{Environment.NewLine}" +
                $"{separator}{Environment.NewLine}" +
                $"{this.Description}{Environment.NewLine}" +
                $"{separator}" +
                $"{allExits}";
        }

        return narration;
    }

    public static void Main(string[] args)
    {
        var kitchen = new Version01_MutableLocation();
        kitchen.Name = "Kitchen";
        kitchen.Description = "You are in a messy kitchen.";

        var library = new Version01_MutableLocation();
        kitchen.Name = "Library";
        kitchen.Description = "You are in the library.";

        var office = new Version01_MutableLocation();
        office.Name = "Office";
        office.Description = "You are in the office. There's a computer on the desk.";

        kitchen.North = library;
        library.South = kitchen;
        library.North = office;
        office.South = library;

        Console.WriteLine($"{kitchen.Narrate()}");
        Console.WriteLine($"{library.Narrate()}");
        Console.WriteLine($"{office.Narrate()}");
    }
}

The following code example implements Narrate() as a static method in which it's dependency is passed in via the method's argument list. The Main() method demonstrates how this class is used within client code (take note of how output is written):

public sealed class Version02_MutableLocation
{
    public string Name { get; set; }
    public string Description { get; set; }
    public Version02_MutableLocation North { get; set; }
    public Version02_MutableLocation South { get; set; }
    public Version02_MutableLocation East { get; set; }
    public Version02_MutableLocation West { get; set; }

    /// <summary>
    /// This static method is a pure function, and all of its dependencies are passed in the function's argument list.
    /// </summary>
    public static string Narrate(Version02_MutableLocation location)
    {
        string narration = string.Empty;

        { // This block constructs the string that is the description
          // of the location that is displayed onscreen to the game player.
            string northExit =
                null != location.North ? " North" : string.Empty;

            string southExit =
                null != location.South ? " South" : string.Empty;

            string eastExit = 
                null != location.East ? " East" : string.Empty;

            string westExit = 
                null != location.West ? " West" : string.Empty;

            string allExits =
                string.Empty != string.Concat(northExit, southExit, eastExit, westExit)
                ? $"{Environment.NewLine}Exits:{northExit}{southExit}{eastExit}{westExit}"
                : string.Empty;

            string separator = new string('-', location.Name.Length);

            narration =
                $"{location.Name}{Environment.NewLine}" +
                $"{separator}{Environment.NewLine}" +
                $"{location.Description}{Environment.NewLine}" +
                $"{separator}" +
                $"{allExits}";
        }

        return narration;
    }

    public static void Main(string[] args)
    {
        var kitchen = new Version02_MutableLocation();
        kitchen.Name = "Kitchen";
        kitchen.Description = "You are in a messy kitchen.";

        var library = new Version02_MutableLocation();
        kitchen.Name = "Library";
        kitchen.Description = "You are in the library.";

        var office = new Version02_MutableLocation();
        office.Name = "Office";
        office.Description = "You are in the office. There's a computer on the desk.";

        kitchen.North = library;
        library.South = kitchen;
        library.North = office;
        office.South = library;

        Console.WriteLine($"{Version02_MutableLocation.Narrate(kitchen)}");
        Console.WriteLine($"{Version02_MutableLocation.Narrate(library)}");
        Console.WriteLine($"{Version02_MutableLocation.Narrate(office)}");
    }
}
Was it helpful?

Solution

According to Microsoft (https://msdn.microsoft.com/en-us/library/w86s7x04.aspx)

The body of the get accessor resembles that of a method. It must return a value of the property type. The execution of the get accessor is equivalent to reading the value of the field. For example, when you are returning the private variable from the get accessor and optimizations are enabled, the call to the get accessor method is inlined by the compiler so there is no method-call overhead. However, a virtual get accessor method cannot be inlined because the compiler does not know at compile-time which method may actually be called at run time.

So according to this it sounds like the answer is no. This paragraph implicitly seems to prove it by not differentiating internal, and external access. If there were a difference, it would have to be mentioned here.

However, in your example, I'd argue that there is an unwanted performance side effect that results from how you chose to present this problem to us. If you limited the question to just asking about property access without reference to how the problem is set up, I'd say the above paragraph proves a 'no' answer.

Since you included a situational context, I'd say there is a slight performance difference. It's not because of property access, but rather it's due to the fact that you're adding another reference to the object through the argument.

Licensed under: CC-BY-SA with attribution
scroll top