4

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)}");
    }
}
  • Closures capture local variables which are regarded as "implicit parameters." If those local variables are immutable, then the resulting function is considered pure. – Robert Harvey Oct 25 '16 at 21:04
  • 1
  • 1
    The first version, because Version01_MutableLocation knows how to narrate itself. – Robert Harvey Oct 25 '16 at 21:41
  • 2
    I know this isn't code review, but e.g. null != location.South ? " South" : string.Empty; should be written as location.South != null ? " South" : string.Empty;. It's considered good style (in any language) for the variable to be on the left and the constant on the right. – gardenhead Oct 25 '16 at 21:56
  • 2
    @gardenhead: In ye olden dayes, programmers sometimes put the constant expression on the left to force the compiler to throw a hissy if = was accidentally used instead of ==. Most modern compilers will warn you regardless. – Robert Harvey Oct 25 '16 at 22:26
0

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.

  • So you're suggesting that, within the context of my 2nd code example, the explicit parameter adds an additional reference, which hampers performance? This makes sense. Would you have any comments about how the readability of code is affected (comparing the two implementations I've listed)? – Rock Anthony Johnson Oct 26 '16 at 15:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.