RemObjects Software Gears
 
       

Partial Methods

{#} by marc hoffman 08/28/07 12:53:20 am, 754 words, Categories: RemObjects, Oxygene, .NET, Visual Studio, Mono, Cocoa, Mac

Next to the big two new features shipping in Version 2.0.3 of Chrome ‘Joyride’ that we’ve already talked about in previous posts, there’s also one small but powerful new language feature that’s new as well: Partial Methods.

What are partial methods? I’m glad you asked. Partial Methods tie in with another related feature we have been supporting for a while now (are, in fact, supporting for .NET 1.1 as the only language i know of) that you are probably familiar with: Partial Classes. Partial classes allow to split the definition of a single class across multiple source files. From looking at the code, each partial looks like a complete class on its own, but at compile time, all parts will be combined into a single class. Because the separate parts form the same class, members defined in one of the parts are accessible from any part.

Partial Classes come in handy for many scenarios, the most commonly seen being the combination of one auto-generated and one user-written file, as used by the form designer, strongly typed data sets, XAML, and other technologies. One code file is generated by a tool and will usually not be touched by the user (might in fact get overwritten regularly) while the user provides a second code file to add her own members to the same class. But even in hand-written code, partial classes come in handy to split large classes into more concise section - for example our own CodeDom implementation uses separate partials to implement different aspects of the code generator - one deals with actual codegen, one contains methods relating to ASP.NET compilation, etc.

Ok, enough about classes, where to partial methods fit in?

Simple: partial methods allow one part of a partial class to define an empty method stub, without providing an implementation. Another part of the class can then choose to (or choose not to) provide an actual method body.

Let’s look at an example. A partial class generated by some tool might define the following:

type
  Foo = partial class
  private
    method Initialize; empty; partial;
  public
    constructor;
  end;

Note how the Initialize method is declared with both the empty and partial keywords. This method is a partial stub that provides no actual implementation - but still, it exists inside the class, and can be called from any of the partials. In this case, it sees likely that the constructor would probably call Initialize at some stage.

A second partial for the Foo class could now go ahead and provide an implementation for the method, by declaring

method Initialize; partial;

Note how the empty keyword is omitted this time, and a full method body will need to be provided in the implementation section - just as for any other method. Any call to Initialize() - from within either part - will then, of course, invoke the provided method implementation.
What happens if no partial provides an implementation for the method stub? Easy: any and all calls to Initialize() will be eliminated by the compiler, and it will be as if the partial method never existed. Thus, a partial method that does not provide an implementation has no runtime overhead, making partial methods an ideal candidate to provide entry points that might or might not be filled.

Now, where are partial methods used in real life?

In Chrome, there are currently two technologies that use partial methods, one shipping in 2.0.3, and one not yet.

Available now, the new Cocoa# template i wrote about before uses partial methods to expose events. Chrome provides a custom tool that generates code from a .NIB (short for NeXT Interface Builder) file that contains the User Interface definition for a Cocoa application. For any events defined in the interface, partial method stubs are provided that the developer can that provide implementations for, if he wants to handle the event. In addition, a third partial will be added to the template for 2.0.5, exposing certain standard events available system-wide from the Cocoa framework but not defined in the .NIB

Secondly, and not yet available but shipping in a future release, code generation for LINQ to SQL will rely on partial methods to provide hooks in the auto-generated code that the user can extend. Due to the zero-overhead nature of partial methods, these hooks can be provided without affecting the runtime behavior - code for them will only be executed if the user provides an implementation.

Oh, and of course there’s also full Code Completion for partial methods, showing you available (and not yet implemented) stubs:


Comments, Pingbacks:

Comment from: Jolyon Smith [Visitor]
What happens if an empty partial method is provided with TWO (or more) partial implementations?

Partial methods and partial classes both to me look like sticking plaster solutions to problems caused by infrastructural holes in certain languages/runtimes.

I can see their uses, but I can also see that they will be storing up HUGE maintenance issues for what will be the legacy code of the future in the absence of comprehensive project documentation (the lack of which, ime, is the only constant in the software development industry).

PermalinkPermalink 08/28/07 @ 01:24
Comment from: C Johnson [Visitor]
Sounds like kludgy detection for dead code removal. Was there a patent that prevented you from just figuring this out automagically?
PermalinkPermalink 08/28/07 @ 02:38
Comment from: Carlo Kok [Member] Email · http://carlo-kok.com/
Jolyon: Just as for regular methods, only 1 implementation is allowed for a partial method. The methods already show up in Code Completion, both for implementing (after method| in a class you can implement them) and calling them (show a different icon).

C. Johnson: The compiler already removes private empty method calls. The Partial modifier allows you to have a way to predefine methods in one partial class (usually generated by an automatic code generator like for example LINQ) and optionally implementing them in the other side of the class.
PermalinkPermalink 08/28/07 @ 11:18
Comment from: C Johnson [Visitor]
I guess I fail to see the point then.

Why would you define a method you never call, particularilly private/protected?

If you do call it, why would you leave it undefined in the hopes that someone else does? (Oh look, you code doesn't compile because there is a hidden requirement to declare code in source you never look at! Errors make a language HARDER to use, not easier, so this seems even odded as a glue of some sort)
PermalinkPermalink 08/28/07 @ 21:12
Comment from: marc hoffman [Member] Email
C: i think you're misunderstanding this entirely. the whole point of the partial method is that there WON'T be an error, if no implementation is provided. This allows one partial (usually the tool-generated one) to provide a point that the user CAN or CAN NOT extend, depending ion his needs
PermalinkPermalink 08/28/07 @ 21:45
Comment from: Jolyon Smith [Visitor]
And when a project suddenly finds itself with two implementations for a previously empty (or satisfactorily "filled" partial method) what is the mechanism for resolving this?

The point being - when I look at the class I see an empty method. When I look at any individual "fragment" I see a satisfactorily completed method and I have no way of knowing that any other fragments (if any) even exist.

So if I have a fragment that doesn't provide an implementation, and the fragment that DOES provide an implementation is not part of the project (which will still compile anyway, since a partial class only needs to be as complete as it is determined to be by included fragments - there is no way that a class can "know" that it has ALL of it's fragments, right?) then one day someone is going to put all those individually valid fragments together and wonder why on earth the thing doesn't compile.

Hey Bob - This CustomerOrder class - does it compile in your project?

Erm, hang on... yes

That's strange - It compiles in this project too, but Debbie says it won't compile in her project. What's going on.... ?


Hence - a future maintenance nightmare, lurking under the bed.

:(

(Please don't try to assure me that "it won't happen if you have proper project management and documentation practises in place" - I would most likely die laughing)

;)
PermalinkPermalink 08/29/07 @ 02:01
Comment from: marc hoffman [Member] Email
Jolyon:

"And when a project suddenly finds itself with two implementations for a previously empty (or satisfactorily "filled" partial method) what is the mechanism for resolving this?"

the same way this gets handled if you provide duplicate implementations of any normal method of course - you'll get an error about the method being duplicate.

"and the fragment that DOES provide an implementation is not part of the project"

if a fragment is not part of the project, it won't be compiled in. the "problem" you are describing is really unrelated to partial methods or not. with partial classes, you *always* have to look at both/all parts to get a clear picture of what's in the class.

That said, Code Completion will help you greatly to show what partials are available for implementing, as (inside the class declaration), it will only show you those methods that are still "up for grabs". Note how in the screenshot "sayIt" and "stopit" do *not* show up anymore because they already have an implementation.

"Hey Bob - This CustomerOrder class - does it compile in your project?"

i mean no offense by saying this, but this comment shows you're approaching this with a Delphi mentality. In .NET, source files are tied to a particular project. If you reuse them, you reuse the assembly that contains them. As such, classes - partial or not - will not usually be linked into different projects that they were not directly written for.

THAT said: even if they were, partial classes would be the least of all issues that could could make code compile in one and not compile in another project - what about availability of other classes *used* by the class in question? external references? etc etc.
PermalinkPermalink 08/29/07 @ 09:55
Comment from: Hallvard Vassbotn [Visitor] · http://hallvards.blogspor.com/
Interesting concept.

It's almost as declaring a virtual abstract method in the declaring partial class and overriding it in the optionally implementing partial class. But beacuse you know there can be only one (or zero) implementation, you can omit the virtual dispatch and even optimize away the call.

In that case, would the partial method be visible via Reflection? I guess not.

So this implies that you cannot have partial methods that return values via a function result or out parameter, right?

I can see the uses for this, but you have to be careful not to use partial methods where using virtuals would have been better. I think it could lead to less extensibility and the singleton class problem. I.e. if you have one class "overriding" (implementing) a partial method, you can have no other class doing the same.

I'm not sure I like the naming; partial indicates (to me) that there are several parts of the implementation (not just one). How about 'optional' instead?
PermalinkPermalink 08/29/07 @ 10:35
Comment from: marc hoffman [Member] Email
Hallvard:

"It's almost as declaring a virtual abstract method in the declaring partial class..."

thats an excellent analogy, yes.

"In that case, would the partial method be visible via Reflection? I guess not."

no, the on-implemented partial method would be completely optimized away and not exist in the resulting assembly.

"I can see the uses for this, but you have to be careful not to use partial methods where using virtuals would have been better."

note that partial methods will ONLY be applicable within the same class; they can't be implemented by a descendant (that's what a "virtual; empty;" method would be used for). To the descendant class the method is ether there (like any normal method) or not, depending on whether an implementation is provided.

"I'm not sure I like the naming"

we debated this quite a bit internally, as well. our reasons fr going with partial include (a) they are tied to partial classes (b) we could avoid adding a new keyword to the language and (c) it's the same terminology C# uses.
PermalinkPermalink 08/29/07 @ 11:57
Comment from: Jolyon Smith [Visitor]
You're right on a number of counts - my concerns stem fundamentally from partial classes themselves, not just partial methods.

The idea that a piece of source is not only incomplete but has no content or mechanism that can reliably indicate when it IS complete I find deeply worrying. I cannot think of any other industry where this would be considered "a good thing".

The other count on which you have me "bang to rights" is that yes, I am thinking with my Delphi "Hat" on, since this partial class concept is coming to Win32 Delphi (may in fact have already arrived) dues to the CodeGear obsession with compatability between Win32 and .NET Delphi compilers.

The idea itself is deeply suspect in itself (a language "feature" born from a shortcoming in an IDE product for crying out loud), even in .NET where there are perhaps checks and balances that can help mitigate the problems that it will cause.

But on Win32..... oh lordy.
PermalinkPermalink 08/30/07 @ 02:14
Comment from: marc hoffman [Member] Email
Jolyon:

"indicate what is complete"

again, i think, the different philosophies in Delphi and .NET are a work here. Yes, in Delphi you can take any one unit, look at it, recursively look at all uses, and you have a complete tree of what's needed to build the thing.

Not so much in .NET (including C#, VB or Chrome). You cant just take a single source file and see what's needed; the classes in the file will most likely rely on other classes in the same namespace, and even for external classes, it's not clear what references are needed just by looking at the used namespaces.

in .NET, the *PROJECT* defines the context, and the external references, not the individual source file. a source file will (almost) never be "complete".

"shortcomings of the IDE"

i have to disagree here. WinForms was continuously (and in that respect rightfully) dissed as flawed by Delphi people because "it stored the form data in the source file", unlike the VCL.

But think about it: the VCL *too* relies on storing parts of the form design (the fields), so it really only provides half-hearted separation between the two.

With XAML, Microsoft addressed this issue, and (again, rightfully) went a step further the the IDE by *COMPLETELY* eliminating tool-generated changes in the user source and no longer needing the fields declared there.

The approach used with partial classes is imho very elegant and flexible, ad imho the logical next step to surpass both the WinForms and VCL way of handling this.
PermalinkPermalink 08/30/07 @ 10:51
Comment from: Hallvard Vassbotn [Visitor] · http://hallvards.blogspot.com/
>>you have to be careful not to use partial methods where using virtuals would have been better."

>note that partial methods will ONLY be applicable within the same class;

Yes, that was my point, actually.

You have to be careful - when /designing/ your application classes, not to use partial classes/methods where you should have used virtual methods and inheritance. The latter gives more flexibility (at a minuscle run-time cost).

Partial classes/methods solve a different problem. Use the right tool for the right job, and all that... ;)
PermalinkPermalink 08/30/07 @ 11:06
Comment from: marc hoffman [Member] Email
Hallvard: i see, yes. I agree that partial classes are a language feature that should be used *sparsely* in user-written code. It has some applications beyond tool-generated classes, but just because it's there certainly doesn't mean that should be use excessively.

i have an example where used partial classes ourselves, in Chrome, and - to be honest - that is the *only* place i've ever used them "manually", ad it was an extreme case because the CodeDom class really is *huge* ad does several different and only vaguely related things (and the framework dictated the class architecture, here).

in general, i agree: if you find yourself using a partial class in "normal" (again, non-tool) code, chances are you want to reconsider your architecture ;).

But - (almost) every language feature has its uses and abuses. that doesn't make it a bad feature. To quote UHF: "Guns don't kill people. I kill people." ;)
PermalinkPermalink 08/30/07 @ 11:18
Comment from: Jolyon Smith [Visitor] · http://www.deltics.co.nz
"Yes, in Delphi you can take any one unit, look at it, recursively look at all uses, and you have a complete tree of what's needed to build the thing."

... and having done that may find that you still haven't identified all the things needed to build the thing if a partial class fragment is involved that is not itself used by those units.... the lack of a mandatory "build list" in a Delphi project exacerbates the problem, since you can't even look at the project source to see what units may be needed EXplicitly but have been forgotten/overlooked.


"dissed as flawed by Delphi people because "it stored the form data in the source file", unlike the VCL."

Storing the form data in the source file wasn't the "problem" for me. The VCL _DOES_ store the form data in the source too, after all:

{$R *.DFM}

The field declarations in the form class are actually "a good thing" imho since it properly reflects in the declaration of the class, the things that that class contains (i.e. references to the "things" in the form) - the way that those references are hooked up to design time elements is what is "neat" in Delphi. Much neater and cleaner than having a chunk of code wrapped inside a "do not touch this" comment and a folding region to try and keep it out of the way.

The VCL method has it's own problems of course, but cluttering up the source code and needing to find a language feature to help the IDE "stay out of the way" wasn't (and isn't) one of them.

;)


I haven't yet looked at XAML so can't comment directly on that, and so won't.

:D


"But - (almost) every language feature has its uses and abuses. that doesn't make it a bad feature."

Absolutely, but the problem is, not everyon that uses these feature will appreciate (or even acknowledge) their dangers.

For sure any language feature can be abused, and that shouldn't be an argument for NOT innovating - if there is a genuine need and a tangible benefit.

I can see NO _need_ for partial classes outside of IDE design considerations. My guess is that partial classes exist not because they are a useful and beneficial addition to any language, but simply because someone had this really cool idea about how they could fix a particular problem without properly thinking about the implications.

NIce quote about guns....

Did you know, the machine gun was invented to SAVE lives? The incentor (a doctor if I remember correctly) figured that if an army could equip one soldier with a weapon that made him as effective as 20, then armies would be 20x smaller and so fewer lives would be lost.

A great idea. No faulting the logic.

I guess he didn't stop to think what would happen if armies stayed the same size but every soldier was given that 20x increase in killing effectiveness.......

The human factor b***ers up great ideas all the frikking time.

:)
PermalinkPermalink 08/30/07 @ 23:46

Leave a comment:

Your email address will not be displayed on this site.
Your URL will be displayed.

Allowed XHTML tags: <p, ul, ol, li, dl, dt, dd, address, blockquote, ins, del, span, bdo, br, em, strong, dfn, code, samp, kdb, var, cite, abbr, acronym, q, sub, sup, tt, i, b, big, small>
(Line breaks become <br />)
(Set cookies for name, email and url)
(Allow users to contact you through a message form (your email will NOT be displayed.))
This is a captcha-picture. It is used to prevent mass-access by robots.
Please enter the characters from the image above. (case insensitive)

 

marc hoffman

Chief Software Architect &
Spare-time Photographer

mh

Links

Twitter

marc hoffman (follow)
    loading...
Mike Orriss (follow)
    loading...

Navigation

XML Feeds 

Who's Online?

  • Guest Users: 7