views:

355

answers:

7

According to this http://msdn.microsoft.com/en-us/library/wa80x488.aspx

"Partial methods are implicitly private"

So you can have this

// Definition in file1.cs
partial void Method1();

// Implementation in file2.cs
partial void Method1()
{
  // method body
}

But you cant have this

// Definition in file1.cs
public partial void Method1();

// Implementation in file2.cs
public partial void Method1()
{
  // method body
}

But why is this? Is there some reason the compiler cant handle public partial methods?

A: 

Not sure if this will answer your question, it did answer mine. Partial Methods

Excerpts:

If you were allow to return something, and were in turn using that as a return value from your CallMyMethods fuction, you would run into trouble when the partial methods were not implemented.

o.k.w
+3  A: 

If you don't define the method, what should the compiler do?

If you don't define them, partial methods will not be compiled at all.
This is only possible because the compiler knows where all of the calls to the method are. If the method isn't defined, it will completely remove the lines of code that call the method. (This is also why they can only return void)

If the method is public, this can't work, because the method might be called by a different assembly, which the compiler has no control over.

SLaks
This isn't right, because partials are resolved at the compiler level. The assembly will have no information in it that the type was partial or non-partial. So, if there's no implementation for the public partial, it would stand to reason that the compiler would throw an error at that point.
David Pfeffer
Isn't that more or less what I said?
SLaks
My point is that since the compiler handles the resolution of partials, it would know ahead of time whether or not an implementation existed. An error would be generated at that point regarding the missing method body, long before any code could be implemented outside of the class that calls that method.
David Pfeffer
Yes, but that defeats the point. Whether you have a `partial` or not, you'll still get a compile-time error if the method body is not defined, so why bother?
SLaks
OK, that does make sense.
David Pfeffer
Why was this downvoted?
SLaks
I dont think my question was clear enough."If you don't define the method, what should the compiler do?" My question was not about methods with no definition. I want to split the method definition across multiple files (a single partial class). This way I can separate the documentation out into a different file while not polluting the implementation.
Simon
I have updated the title to reflect this
Simon
+10  A: 

Partial methods have to be completely resolvable at compile time. If they are not there at compile time, they are completely missing from the output. The entire reason partial methods work is that removing them has no impact on the API or program flow outside of the one line calling site (which, also, is why they have to return void).

When you add a method to your public API - you're defining a contract for other objects. Since the entire point of a partial method is to make it optional, you'd basically be saying: "I have a contract you can rely on. Oh wait, you can't rely on this method, though."

In order for the public API to be reasonable, the partial method has to really either always be there, or always be gone - in which case it shouldn't be partial.

In theory, the language designers could have changed the way partial methods work, in order to allow this. Instead of removing them from everywhere they were called, they could have implemented them using a stub (ie: a method that does nothing). This would not be as efficient, and is unnecessary for the use case envisioned by partial methods, though.

Reed Copsey
Correct. Doing so would totally defeat the purpose of partial methods, namely that they are "pay for play" in metadata burden. You can have a thousand partial methods, and if you define only one of them, you get metadata emitted for that one method, not for all thousand them. We designed partial methods for machine-generated coding scenarios where there could literally be thousands of them, and we don't want to bloat metadata.
Eric Lippert
Yeah - that was what I was trying to say - you ~could~ have designed them that way, but it would have changed their meaning dramatically.
Reed Copsey
ReedI dont think i was clear enough with my question. my scenerio is having both the implementation and the definition in the same assembly. I have updated the title to reflect this.
Simon
The thing is - when you define it public, you're saying "This is my contract". If you were to drop out methods, at whim, why make them public in the first place? Public really means ANYBODY (whether in the same assembly or a different one) can use that method...
Reed Copsey
Reed. While you make some interesting points you still have not given me a technical reason as to why, when there is at least on public implementation, you can’t have public partial methods.
Simon
+6  A: 

Instead of asking why are they private, let's rephrase the question to this:

  • What would happen if partial methods weren't private?

Consider this simple example:

public partial class Calculator
{
    public int Divide(int dividend, int divisor)
    {
        try
        {
            return dividend / divisor;
        }
        catch (DivideByZeroException ex)
        {
            HandleException(ex);
            return 0;
        }
    }

    partial void HandleException(ArithmeticException ex);
}

Let's ignore for the moment the question of why we would make this a partial method as opposed to an abstract one (I'll come back to that). What's important is that this compiles - and works correctly - whether the HandleException method is implemented or not. If nobody implements it, this just eats the exception and returns 0.

Now let's change the rules, say that the partial method could be protected:

public partial class Calculator
{
    // Snip other methods

    // Invalid code
    partial protected virtual void HandleException(ArithmeticException ex);
}

public class LoggingCalculator : Calculator
{
    protected override virtual void HandleException(ArithmeticException ex)
    {
        LogException(ex);
        base.HandleException(ex);
    }

    private void LogException(ArithmeticException ex) { ... }
}

We have a bit of a problem here. We've "overridden" the HandleException method, except that there's no method to override yet. And I mean the method literally does not exist, it's not getting compiled at all.

What does it mean what our base Calculator invokes HandleException? Should it invoke the derived (overridden) method? If so, what code does the compiler emit for the base HandleException method? Should it be turned into an abstract method? An empty method? And what happens when the derived method calls base.HandleException? Is this supposed to just do nothing? Raise a MethodNotFoundException? It's really hard to follow the principle of least surprise here; almost anything you do is going to be surprising.

Or maybe nothing should happen when HandleException is invoked, because the base method wasn't implemented. This doesn't seem very intuitive, though. Our derived class has gone and implemented this method and the base class has gone and pulled the rug out from under it without us knowing. I can easily imagine some poor developer pulling his hair out, unable to figure out why his overridden method is never getting executed.

Or maybe this code shouldn't compile at all or should produce a warning. But this has a number of problems of its own. Most importantly, it breaks the contract provided by partial methods, which says that neglecting to implement one should never result in a compiler error. You have a base class which is humming along just fine, and then, by virtue of the fact that someone implemented a totally valid derived class in some completely different part of the application, suddenly your app is broken.

And I haven't even started talking about the possibility of the base and derived classes being in different assemblies. What happens if you reference an assembly with a base class that contains a "public" partial method, and you try to override it in a derived class in another assembly? Is the base method there, or not there? What if, originally, the method was implemented, and we wrote a bunch of code against it, but somebody decided to remove the implementation? The compiler has no way to stub out the partial method calls from referencing classes because as far as the compiler is concerned, that method never existed in the first place. It's not there, it's not in the compiled assembly's IL anymore. So now, simply by removing the implementation of a partial method, which is supposed to have no ill effects, we've gone and broken a whole bunch of dependent code.

Now some people might be saying, "so what, I know that I'm not going to try to do this illegal stuff with partial methods." The thing you have to understand is that partial methods - much like partial classes - are primarily intended to help simplify the task of code generation. It's very unlikely that you would ever want to write a partial method yourself period. With machine-generated code, on the other hand, it's actually fairly likely that consumers of the code will want to "inject" code at various locations, and partial methods provide a clean way of doing this.

And therein lies the problem. If you introduce the possibility of compile-time errors due to partial methods, you've created a situation in which the code generator generates code that doesn't compile. This is a very, very bad situation to be in. Think about what you'd do if your favourite designer tool - say Linq to SQL, or the Winforms or ASP.NET designer, suddenly started producing code that sometimes fails to compile, all because some other programmer created some other class that you've never even seen before that happens to have become a little too intimate with the partial method?

In the end it really boils down to a much simpler question, though: What would public/protected partial methods add that you can't already accomplish with abstract methods? The idea behind partials is that you can put them on concrete classes and they'll still compile. Or rather, they won't compile, but they won't produce an error either, they will just be completely ignored. But if you expect them to be called publicly, then they aren't really "optional" anymore, and if you expect them to be overridden in a derived class, then you might as well just make it abstract or virtual and empty. There isn't really any use for a public or protected partial method, other than to confuse the compiler and the poor bastard trying to make sense of it all.

So instead of opening up that Pandora's box, the team said forget it - public/protected partial methods aren't much use anyway, so just make them private. That way we can keep everything safe and sane. And it is. As long as partial methods stay private, they are easy to understand and worry-free. Let's keep it that way!

Aaronaught
But my example does not have any inheritance. I simply want to have comments and/or attributes in a separate file to the implementation
Simon
@Simon: Why would it matter if "your example" does not make use of a particular construct? I am explaining why the feature can't be implemented safely. You are not the only user of the C# compiler. Furthermore, as I explained above, partial methods are designed for use in code generation; your use case is probably not even on the radar.
Aaronaught
@Simon: And more importantly, your use case is even more dangerous than the above. What if anyone, anywhere, could add the `[Conditional]` or `[MethodImpl]` attributes? This means that other people could introduce major and potentially breaking changes to your class at compile time. A class needs to be able to maintain its own invariants; allowing arbitrary extension of public methods in this fashion completely blows that away. Even the ability of an external actor to change the documentation seems contrived; why would you want to allow this?
Aaronaught
+1  A: 

Reed's and Slak's answers are entirely correct but you seem unwilling to accept their answers.

I will thus try to explain why partial methods are implemented with these restrictions.

Partial methods are for implementing certain sorts of code gen scenarios with maximal efficiency, both in execution time and in meta data overhead. The last part is the real reason for them since they are attempting to make them (in Erics words) "Pay for play".

When partial methods were added the JIT was entirely capable of inlining an empty method, and thus it having zero runtime effort at the call sites. The problem is that even then there is a cost involved which is that the meta data for the class will have these empty methods increasing their size (needlessly) as well as forcing some more effort during the JITing process to deal with optimizing them away.

Whilst you may not worry too much this cost (and indeed many people won't notice it at all) it does make a big difference to code where startup cost matters, or where disk/memory is constrained. You may have noticed the now mandatory use of .Net on windows mobile 7 and the Zune, in these areas bloat on type metadata is a considerable cost.

Thus partial methods are designed such that, if they are never used they have absolutely zero cost, they cease to exist in the output in any way. This comes with some significant constraints to ensure this does not result in bugs.

Taken from the msdn page with my notes.

  • ...the method must return void.
  • Partial methods can have ref but not out parameters.

Otherwise removing the call to them may leave you with an undefined problem of what to replace the assignment with.

  • Partial methods cannot be extern, because the presence of the body determines whether they are defining or implementing.
  • You can make a delegate to a partial method that has been defined and implemented, but not to a partial method that has only been defined.

These follow from the fact the compiler needs to know if it's defined or not, and thus is safe for removal. This leads us to the one you dislike.

  • Partial methods are implicitly private, and therefore they cannot be virtual.

Your metal model of this feature is that, if the compiler knows that a partial method is implemented then it should simply allow the partial method to be public (and virtual for that matter) since it can check that you implemented the method.

Were you to change the feature to do this you have two options:

  1. Force all non private partial methods to require implementation.

    • simple and not likely to involve much effort but then any such methods are no longer partial in the meaningful sense of the original plan.
  2. Any method declared public is simply deleted if it was not implemented in the assembly.

    • This allows the partial removal to be applied
    • It requires quite a lot more effort by the compiler (to detect all references to the method rather than simply needing to look in the composed class itself)
    • The IntelliSense implementation is a bit confused, should the method be shown? sown only when it's been given a definition?
    • Overload resolution becomes much more complex since you need to decide whether a call to such a method with no definition is either a) a compile time failure or b) results in the selection of the next best option if available.
    • Side effects within expressions at the call sites are already complex in the private only case. This is mitigated somewhat by the assumption that partial implementations already exhibit a high degree of coupling. This change would increase the potential for coupling.
    • This has rather complex failure modes in that public methods could be silently deleted by some innocuous change in the original assembly. Other assemblies depending on this one would fail (at compile time) but with a very confusing error (without considerable effort this would apply even to projects in the same solution).

Solution 1 is simply pointless, it adds effort and is of no benefit to the original goals. Worse it may actually hinder the original goals since someone using partial methods this way may not realise they are gaining no reduction in metadata. Also someone may become confused about the errors that result from failing to supply the definition.

That leaves us with solution 2. This solution involves effort (and every feature starts with -100) so it must add some compelling benefit to get it over the -100 (and the additional negatives added for the confusion caused by not the additional edge cases). What scenarios can you come up with to get things positive?

Your motivating example in the comments above was to "have comments/and or attributes in a different file"

The motivation for XML comments was entirely to increase the locality of documentation and code. If their verbosity is high then outlining exists to mitigate this. My opinion is that this is not sufficient to merit the feature.

The ability to push attributes to a separate location is not in my view that useful, in fact I think having to look in two locations is more confusing. The current private only implementation has this problem too, but it is inevitable and again is mitigated somewhat by the assumption that high coupling that is not visible outside of the class is not as bad as high coupling external to the class.

If you can demonstrate some other compelling reason I'm sure it would be interesting, but the negatives to overcome are considerable.

ShuggyCoUk
A: 

The simple reasons is that partial methods are not public because they are an implementation detail. They are meant primarily to support designer related scenarios and are not ever meant to be part of a supported public API. A non-public method works just fine here.

Allowing partial methods to be public is a feature. Features have inherent costs including design, testing, development, etc ... Partial methods were just one of the many features added in a very packed Visual Studio 2008. They were scoped to be as small as possible to fit the scenario in order to leave room for more pressing features such as LINQ.

JaredPar
Can you detail further as to why you would ever want to have a partial method? My mind == blown that they even exist in the first place...
Paul Betts
@Paul: They're incredibly useful for designer or template-generated situations. It's handy to have "optional" methods that the designer can fill in, and then allow you to use them if needed. Much less useful for hand-written code.
Reed Copsey
+1  A: 

Because the MS compiler team did not have a requirement to implement this feature.

Here is a possible scenario of what happen inside MS, because VS uses code gen for a lot of its features, one day a MS code gen developer decided that he/she needed to have partial methods so that the code generated api could be extended by outsiders, and this requirement led the compiler team to act and deliver.

John Simons