views:

154

answers:

5

If I have a method for calculating the greatest common divisor of two integers as:

public static int GCD(int a, int b)
{
    return b == 0 ? a : GCD(b, a % b);
}

What would be the best way to attach that to the System.Math class?

Here are the three ways I have come up with:

public static int GCD(this int a, int b)
{
    return b == 0 ? a : b.GCD(a % b);
}

// Lame...

var gcd = a.GCD(b);

and:

public static class RationalMath
{
    public static int GCD(int a, int b)
    {
        return b == 0 ? a : GCD(b, a % b);
    }
}

// Lame...

var gcd = RationalMath.GCD(a, b);

and:

public static int GCD(this Type math, int a, int b)
{
    return b == 0 ? a : typeof(Math).GCD(b, a % b);
}

// Neat?

var gcd = typeof(Math).GCD(a, b);

The desired syntax is Math.GCD since that is the standard for all mathematical functions.

Any suggestions? What should I do to get the desired syntax?

+9  A: 

You cannot. Extension methods are just syntactic sugar for calling a static function and passing an instance of a particular type. Given that, they operate only on instances, as they must be defined by passing a this parameter of the type you want to attach to.

Adam Robinson
This isn't *entirely* accurate, you can call extension methods within the same static class directly.
Nick Craver
What I want is some syntactic sugar to apply to static classes as well...
John Gietzen
@Nick: You can call any extension method directly. What's your point?
Adam Robinson
@John: At this time, that isn't possible. You could submit a feature request to Microsoft, but I honestly wouldn't bet on getting much traction.
Adam Robinson
@Adam - They don't operate only off instances, at least the way you word it, sounds like it must me `myObj.Extension()`, may want to clarify :)
Nick Craver
So, how do i get my desired syntax? That is the question at hand, not necessarily using extension methods directly... Right now, this answer is not helpful. I already fully realize that the extension methods cannot apply to classes themselves...
John Gietzen
@John: Again, what you're asking for is impossible with any version of C# (or any other .NET language). There is not an answer to your question other than "you can't."
Adam Robinson
@Nick: Extension methods operate only off of instances. When calling, say, `Enumerable.Select` directly, you aren't calling an extension method, you're calling a static method on a static class. I didn't see much point (or relevance) in pointing that out.
Adam Robinson
@John: If you are aware of the fact that you cannot apply an extension method to another *class* (only to an *instance*), then what was the point in asking this question?
Adam Robinson
@Adam - `MyExtenson("bob");` for example, or `MyExtension(null)`, that operating off an instance of null? :)
Nick Craver
@Adam: To get my desired syntax... Read the question.
John Gietzen
@Nick: As I said, that's *not an extension method*. That's calling a static method. We can argue semantics if you like, but I don't see any point in talking about an extension method that isn't being used as such.
Adam Robinson
@John: We're going in circles. Your desired syntax is `System.Math.GCD`. I said this is impossible. You said you know that. I asked why you asked the question. You said to get the syntax that you know is impossible. ??? = profit.
Adam Robinson
@Nick: And yes, an extension method can certainly operate (or try to operate) off a `null` reference. `List<string> foo = null; foo.Select(s => s.Replace("bar", "baz"));`
Adam Robinson
@Adam - A null reference yes, but that's not an *instance*, which was my point. I often call extension methods from within others in the same static class without using the `obj.extension()` syntax, but rather `extension(obj)`, this is common behavior, even in the `System.Linq` namespace. It's just worth noting to anyone new that they can be used not **only** in the extension format, which is what your answer (to me at least) conveys with the wording.
Nick Craver
@Nick: `((List<string>)null).Select(...);` Again, *extension methods operate off of instances only*. Calling the method directly as a static method is **not using it as an extension method**. Once more (this time with feeling) **I see no point in discussing the fact that you can call an extension method outside of the extension format in this question, as it has absolutely no relevance to this question**.
Adam Robinson
@Adam - On the contrary, he wants to have static methods on a class and call them directly, I don't see how you can say it's not relevant.
Nick Craver
@Nick: He wants to define static methods on one class and have them apply to another. That's why it's irrelevant.
Adam Robinson
@Adam: No, my desired syntax is `Math.GCD`, without conflicting with `System.Math`, which is (as far as I know) not impossible. I was here looking for suggestions on what syntax to use *if* it is impossible
John Gietzen
@John: If you define your own `Math` class within your namespace, then you will no longer be able to call `System.Math` as just `Math` (you'll have to qualify it as `System.Math`).
Adam Robinson
@John, you're being a tad difficult! You cannot extend System.Math. You already know your options: extension method on int, or a static (whatever)Math class of your own. And, as Adam pointed out, if you opt for My.Math, then you'll have to fully qualify System.Math whenever you need it. Personally, I would go for a static math utility class named something like MathUtility.
Anthony Pegram
@Anthony: Why would I have to qualify `System.Math` if I opt for `My.Math`?
John Gietzen
@John: If you're within the `My` namespace, then `Math` will refer to `My.Math`, not `System.Math`. If you are not within the `My` namespace, then you will have to qualify it as `My.Math` (which does not meet the criteria set up in your question).
Adam Robinson
@Adam: Who said I was in the `My` namespace? Also, I'm looking for *SUGGESTIONS*.
John Gietzen
@John: You stated that you needed to be able to call `Math.GCD`. If you aren't in the namespace of the new static class, then you cannot do that (you'll have to call `My.Math.GCD`). Your question asked "how do I do this?", not "how should I expose an additional math function?" If you're truly looking for suggestions as to how (knowing that your *desired* syntax is, strictly speaking, not possible), why not update the question to reflect this?
Adam Robinson
@John, if you are inside of My or have a 'using My;' statement, you would need to fully qualify System.Math whenever you need it. If you never had that using, you wouldn't need to qualify it. I'll grant that distinction.
Anthony Pegram
@Adam: From the get-go I've been asking for suggestions. The questions above already reflect my desires, no edit necessary. I know that it isn't 100% possible, which is why I gave three examples of ways I have come up with. (None of which, by the way, are tied *strictly* to the desired syntax)
John Gietzen
@John: Clearly you've found an answer to your satisfaction, though it does not fit the criteria outlined by your question.
Adam Robinson
+5  A: 

I would prefer the one with RationalMath. You really don't need extension methods here, because their aim is to mimic instance methods of objects of you can't modify. But here one should use plain old static method.

Andrey
I would name it like <companyName>Math. If really want, you can write wrappers for all the Math functions and then tell all developers to use only <companyName>Math ... but thats probably overkill.
TheSean
@TheSean: I just posted that as an answer as well . . . although I agree that it probably isn't worth it.
Tim Goodman
+4  A: 

Given the fact that you cannot extend the static Math class I would go for sample #2. It follows the pattern used by Math, does not clutter the int method space, and is simple and clean to invoke. #3 is plain horrible :)

Peter Lillevold
I know it is. That's why I'm here. :)
John Gietzen
A: 

Ok, one other way I thought of:

namespace My
{
    public static class Math
    {
    }
}


namespace MainApp
{
    ...
    var gcd = My.Math.GCD(a, b);
    ...
}
John Gietzen
Why was this downvoted?
John Gietzen
+2  A: 

Personally, I wouldn't do it the way you want. System.Math is just one static class that contains some mathematical functions . . . there's no reason it has to contain every mathematical function you'd ever want to use.

However, if you really want this, I suppose you could write your own static Math class that's a sort of wrapper for System.Math . . . basically just implement every function in System.Math by passing it along to the actual System.Math class. Like this:

public static class Math
{

  public static int GCD(int a, int b)
  {
     return b == 0 ? a : GCD(b, a % b);
  }

  // Implement the System.Math methods
  public static double Pow(double x, double y)
  {
    return System.Math.Pow(x, y);
  }
  // etc.
}

This seems like a real pain in the neck though for not much benefit. (Kind of an anti-syntactic sugar.) But it would let you call Math.GCD(a,b) and, say, Math.Pow(x,y) from the same class, which is what it sounds like you want.

Tim Goodman
Yay for real suggestions! I agree that this is overkill, tho.
John Gietzen