14

When setting out good design, which would you choose, extension methods or the visitor pattern?.

Which is easier to design for, when should you use an extension method over a visitor pattern and vice verso?

Is there any good valid reason to use an extension method over a visitor class, apart from syntactical sugar to aid in program readability?

How would you design for a system that incorporates extension methods, would you classify them in a UML diagram?

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }   
}

I may have the wrong pattern, it looks like a visitor pattern from the code above. So I think my comparison holds up.

Some code, I would say that the extension method looks like a visitor pattern.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    #region Interfaces

    public interface IFred
    {
        string Data
        {
            get;
            set;
        }        

        string doSomething();
    }


    public interface IBob
    {
        string Data
        {
            get;
            set;
        }
    }

    #endregion

    #region fred stuff

    public partial class Fred : IFred
    {

        public string doSomething()
        {
            return this.Data + " is really cool";
        }

        public string Value()
        {
            throw new NotImplementedException();
        }

    }

    public partial class Fred
    {
        public string Data
        {
            get;
            set;
        }
    }

    #endregion


    #region bob stuff

    public class BobData : IBob
    {
        public string Data
        {
            get;
            set;
        }
    }

    public class BobData2 : IBob
    {
        private string pData;
        public string Data
        {

            get
            {
                return pData + " and then some!";
            }
            set
            {
                pData = value;
            }
        }
    }

    public class BobVisitor
    {
        public string dosomething(IBob bobData)
        {
            Console.WriteLine(bobData.Data);
            return "ok";
        }

        public string dosomethingOnlyToBob(BobData bobData)
        {
            Console.WriteLine("hello bob version 1");
            return "ok";
        }


        public string dosomethingOnlyToBob2(BobData2 bobData)
        {
            Console.WriteLine("hello bob version 2");
            return "ok";
        }

    }

    #endregion


    public static class Visitor
    {
        public static string visit(this IBob bobObj)
        {
            Console.WriteLine(bobObj.Data);
            return "ok";

        }

        public static string visit(this IFred fredObj)
        {
            Console.WriteLine(fredObj.Data);
            return "ok";
        }
    }


    class Program
    {
        static void Main(string[] args)
        {

            //Another way of abstracting methods from data, using Partial Classes.
            var fredObj = new Fred();
            fredObj.Data = "fred data";
            fredObj.doSomething();


            //Create the bob classes version 1 and 2
            var bobObj = new BobData();
            bobObj.Data = "bob data";

            var bob2Obj = new BobData2();
            bob2Obj.Data = "bob 2 data";


            //using the bobVisitor Class
            var bobVisitor = new BobVisitor();

            bobVisitor.dosomething(bobObj);
            bobVisitor.dosomething(bob2Obj);

            bobVisitor.dosomethingOnlyToBob(bobObj);
            bobVisitor.dosomethingOnlyToBob2(bob2Obj);


            //using the extension methods in the extension class
            bobObj.visit();
            fredObj.visit();

            Console.Read();
        }
    }
}
WeNeedAnswers
  • 4,620
  • 2
  • 32
  • 47
  • 1
    I think that writing an extension method and the visitor pattern are inherently solving the same problem. But with the Visitor pattern you can completely separate the logic from the class. Extension method is kind of adding a method onto the class itself. – lahsrah Aug 04 '11 at 03:56
  • Visitors do separate data from methods. I think that the syntax sugar that extension method classes add, obfuscate to what they really are. I was tempted to call them decorators but on closer examination, they act upon the whole class, check out the syntax. – WeNeedAnswers Aug 04 '11 at 12:19
  • They don't really add anything to the class. Just a bit of sugary magic. – WeNeedAnswers Aug 04 '11 at 12:20

2 Answers2

9

You probably should be comparing the visitor pattern against the template method pattern, as those are two things you can compare and contrast.

Comparing the visitor pattern with extension methods is like comparing a car with a bicycle sprocket.

In any case, extension methods are useful anywhere a non virtual method is useful, with the added bonus that you don't need to own the type to define an extension method.

Both the template method and visitor pattern are design patterns intended to operate over trees of objects. The "classic" definition of both requires a virtual method in each "node type" in the object tree. However, it is possible to implement both using non virtual methods if necessary. There are some limitations, such as access to private and protected members, but ignoring that, either pattern can be implemented with extension methods.

The template method pattern works by adding a virtual method for an operation to each type in the object tree, with "aggregate nodes" calling into to the method on their contained nodes.

An example might be a "print" method for an expression tree.

public class Node
{
   abstract void print();
}

public class AddExpression : Node {
    Node Left;
    Node Right;

    virtual void print() {
        Left.Print();
        Console.WriteLine("+");
        Right.Print();
    }
}

This has a major benefit, in that adding new node types only requires incremental effort. Only the new types need to be changed. It has a drawback, however, in that adding new operations requires editing every single type.

The visitor pattern generalizes template methods into a single method called accept that takes a visitor object as a parameter. It looks something like:

interface Visitor {
    void VisitAdd(AddExpression e);
    void VisitSubtract(SubtractExpression e);
}
abstract class Node {
    abstract void Accept(Visitor v);
}
class AddExpression : Node {
    //...
    virtual void Accept(Visitor v) {
        Left.Accept(v);
        v.VisitAdd(this);
        Right.Accept(v);
    }
}

This has the opposite tradeoffs. Adding new operations only requires writing one new class, but adding a new type requires editing every operation.

The classic advice is to use template method when the operations are (relatively fixed) but new object types can be added frequently. Similarly, visitors should be used when the object typed are fixed, but new operations can be added frequently,

If both change equally, then your decision should be based on balancing:

  1. Clarity (template methods are easier to understand, and avoid the overhead of double dispatch).
  2. Reuse (visitors factor common traversal code into a single place).
Scott Wisniewski
  • 24,561
  • 8
  • 60
  • 89
  • 1
    The tree thing is correct when using a visitor pattern in general. But I am not talking about finite state machines or anthing like that. First I think we need to categorize what an Extension method is, I for one believe its a visitor pattern or maybe a decorator. I would call it a visitor, just by the very design of the class. When used however, the syntax sugar hides what it is. – WeNeedAnswers Aug 04 '11 at 12:29
  • 2
    Huh? An extension method is not a design pattern. It's lower level than a dedign pattern. It's just a type of method. The same way a "for loop" is not a pattern. – Scott Wisniewski Aug 04 '11 at 14:57
  • 1
    A for loop is a pattern. Google it. – WeNeedAnswers Aug 04 '11 at 21:25
  • Some languages don't use for loops at all. Take a look at Haskell and other functional programming languages where the concept of the loop has been pared down to concept rather than an action. – WeNeedAnswers Aug 04 '11 at 21:47
  • I guess it comes down to a definition of what design patterns are. I'm not sure I know anyone who would define an extension method or for loop as design patterns. – Phil Sandler Aug 04 '11 at 21:58
  • @Phil you get the concept that a loop is a programming feature and not a given don't you. I gather you know about the goto statement? – WeNeedAnswers Aug 04 '11 at 22:18
  • Please read the article you cited (the whole article, not just the text at the top). It does not remotely back up your claim that for loops or extension methods are design patterns. There are no design patterns in the given list that are anything like those constructs. BTW, I do not appreciate being called a troll, and this will be my last reply to you. – Phil Sandler Aug 04 '11 at 22:32
  • Iterator Pattern @Phil, as prescribed by the Gof. – WeNeedAnswers Aug 04 '11 at 22:45
  • 5
    The iterator pattern is a design pattern... a for loop is a mechanism for one way of implementing it... – Scott Wisniewski Aug 04 '11 at 22:48
  • 1
    @Scott, some languages opt out of the for loop mechanism, but they to have a need to use a system where they iterate over a series of items in a list. This I would say is a design pattern. The implementation of a for loop should not be confused with the mechanism. I use the Iterator Pattern from the classic Gof as an example of a pattern that is used in OO languages. As you know you could use Array.ForEach to iterate over an array. The actual implementation is hidden away, but the concept is still there, as a pattern. – WeNeedAnswers Aug 05 '11 at 02:33
  • @WeNeedAnswers I know this. Take a look at http://GitHub.com/scottwis/Eddie. It's my dialect of Haskell. It's really really early on though. Anyways, my point was that extension methods are not a design pattern.... – Scott Wisniewski Aug 05 '11 at 03:08
  • @Scott your own dialect. you brave brave man. Will check it out, sounds interesting. – WeNeedAnswers Aug 05 '11 at 03:13
  • @Scott, why did you choose C# for a language why not F#, Python or dare I say Scheme (okay scrap that last one :)) – WeNeedAnswers Aug 05 '11 at 03:33
  • I like the .NET framework. It's an insanely great framework. C# is very well designed. It's the best imperative language there is. It provides enough functional features to implement a "pure language " in a "pure style ", while making the "impure" parts easy to define. Why wouldn't I use it? – Scott Wisniewski Aug 05 '11 at 03:42
  • @Scott I agree about the .net framework as being insanely great, it is. However the syntax of c# doesn't lend itself well to creating other languages within it. Messing about with the mini language creation features of F#, don't you think its more suited to the task? – WeNeedAnswers Aug 05 '11 at 14:04
  • No. My goal with Eddie is to make the good parts of Haskell (non strictness, immutability, monads) accessible to mere mortals. I'm trying to do this by taking the cumbersome parts (the hindly Milner type system, the ml style syntax, implicit currying, explicit monads) and replacing them with more accessible stuff (algol style syntax, explicit typing of declarations, implicit monads, explicit currying).using c#, with discipline, makes bootstraping Eddie easier. – Scott Wisniewski Aug 05 '11 at 17:24
  • I do admit that C# is missing pattern matching (Eddie has it though), but I can write the c# code in a way that I can extract patterns from easily.... – Scott Wisniewski Aug 05 '11 at 17:45
  • I've been that I might actually implement it in Haskell, even though that will make bootstraping more difficult, just because it will force me to use monads a lot, which should make the implementation of monads in Eddie better. The runtime stuff will still be implemented in C# though. – Scott Wisniewski Aug 07 '11 at 16:44
  • @ScottWisniewski, I'm confused by your assertion that "An extension method is not a design pattern". You readily accept that `foreach` is an implementation of the iterator pattern, so why do you have trouble accepting that extension methods are an implementation of the visitor pattern? – David Arno Jan 20 '16 at 13:04
  • 1
    Because extension methods aren't visitors. The visitor pattern is a form of double dispatch generally used for navigating tree structures. An extension method is syntactic sugar for adding a non virtual method to the overload resolution set of a given type. They are completely different things. – Scott Wisniewski Jan 21 '16 at 05:54
0

Extension methods aren't a pattern. They are just some language syntax which makes code easier to read.

Visitor pattern is an entire different beast. I don't really know why you are comparing the two.

tster
  • 17,883
  • 5
  • 53
  • 72
  • 2
    They are a design pattern, just that the syntax sugar hides what they really are. – WeNeedAnswers Aug 04 '11 at 12:21
  • You downvoted this? This is a very valid answer, and one I happen to agree with. Extension methods in c# are syntatic sugar, and are really just static methods at their core. If you ask for opinions in a question, don't downvote when you get opinions as answers. The visitor pattern and extension methods are completely unrelated, and you now have two answers that say so. – Phil Sandler Aug 04 '11 at 13:38
  • 2
    I down voted on the fact that an Extension does form a pattern. It acts upon a passed in object. The pattern repeats itself, that is what a pattern is. You can reuse the pattern over and over again. The fact that the environment sugar coats it nicely, to make such lovelys as Linq look and feel like an SQL type language, does not deter from the fact that an Extension method is a pattern. If you honestly look at Extension methods as just "syntax sugar", then I beg you to look at them again and re-evaluate your opinion. – WeNeedAnswers Aug 04 '11 at 21:30
  • 2
    I also down voted on the fact of the brevity of the answer, and the opinion was given without any thought to the question being asked. It makes one ask if the intention was just to sound smart, and not to answer the question at all. It is so easier to be mysterious and laconic than to be polite, poetic and with some style. It takes time to care, it takes minutes not to give a sh*t. – WeNeedAnswers Aug 04 '11 at 21:37
  • @Phil, like I posted on your question http://stackoverflow.com/questions/1296953/do-extension-methods-hide-dependencies, Did you design for them? – WeNeedAnswers Aug 04 '11 at 21:39
  • Stackoverflow's format is about asking *focused questions*. The answer you posted to my question was completely unrelated. Even so, I won't downvote it. I will vote to close this question, though, since based on your responses here it is clearly not a valid SO question. – Phil Sandler Aug 04 '11 at 21:51
  • 1
    @Phil, so far there hasn't been a response to my question which I feel has answered it. If you have nothing but troll behavior about you I would kindly ask you to leave me be. – WeNeedAnswers Aug 04 '11 at 22:12
  • 4
    @WeeNeedAnswers, Extension methods are nothing other than static methods. Any "pattern" that can be done with extension methods can be done using static methods. Furthermore, extension methods are a language feature, not a pattern. A design pattern is a general solution to a common problem and is (mostly) language agnostic. Extension methods are just a different way of calling static methods in 1 particular language. The brevity of my answer reflects well the lack of focus of the question. If I asked "Please compare a car and a phone", I wouldn't expect any more than "They are different" – tster Aug 05 '11 at 00:00
  • I have given you a point back, because you took the time @tster thank you. However, I disagree about the design pattern stuff as an extension method class is repeated to do the same task over and over which is to allow code to be added that can act upon an instance of a class at run time without changing the actual definition of the static class. – WeNeedAnswers Aug 05 '11 at 02:21
  • I have also added some code to the question to give some examples of what I feel that both Visitor Pattern, Extension methods and to that matter partial classes are trying to achieve, all in very similar ways. I grant you that the static behavior of the Extension method does make it a tad restrictive but not to the extent of being evil. I mean we use static all the time when dealing with strings. – WeNeedAnswers Aug 05 '11 at 02:25
  • I up voted it. I can't stand "purists". After 20 successful years in this career, I have seen that they make a lot of noise and solve nothing. Purists in theory but when it comes to solve a problem, they can't start writing the first line of code.... SMFH. – Pepito Fernandez Mar 03 '16 at 19:20
  • In my opinion, Extension Methods are an implementation of the Visitor Pattern. https://dvanderboom.wordpress.com/2008/04/09/the-visitor-pattern-in-c-30/ – Pepito Fernandez Mar 03 '16 at 20:00
  • you can't have the visitor pattern without polymorphism, which static methods don't participate in. The blog post you posted looks to me more like someone who doesn't like the visitor pattern and is looking for a way to accomplish the same thing without it. – tster Mar 03 '16 at 21:39