Skip to content

Remove extension methods #1093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jun 19, 2015
Merged

Remove extension methods #1093

merged 15 commits into from
Jun 19, 2015

Conversation

nulltoken
Copy link
Member

Preliminary step to #1076

@ethomson
Copy link
Member

Why Extension methods? As a LibGit2Sharp developer, I find it really hard to find these overloads when they're off hiding if DiffExtensions.cs instead of Diff.cs...

Just my $0.02.

@nulltoken
Copy link
Member Author

Why Extension methods?

Well, most of the overloads already live in xxxExtensions.cs files.
Besides, I find that helps keeping the files holding the concrete logic less lengthy and easier to navigate.
Somehow, I see them as an additional/optional layer on top of the real API.

However, I agree that none of those arguments are pure, undeniable and objective ones. As such, maybe would it be the proper time to make a final decision (BTW, I thank you @ethomson for having raised this before I'm done coding this PR 😉)

Who's in favor of xxxExtensions? Who think they bring more pain than value?
Should we keep them or 🔫 🔥 💀 them?

/cc @bording @carlosmn @dahlbyk @jamill @jeffhostetler @shiftkey @whoisj

@Therzok
Copy link
Member

Therzok commented Jun 15, 2015

feels ignored

I'm in favor of Extension methods. I've never been a fan of all overloads functions in one place, especially when they're convenience functions provided to transform some parameters into others, or use default values in place of parameters aka just wrappers.

@whoisj
Copy link

whoisj commented Jun 15, 2015

Generally I'm either for or agnostic of extension methods in C# due the way the compiler and runtime work to make it "just work". However, I do not believe we should be moving virtual methods from an inheritable class into extension methods. Doing so effectively takes control away from the inheritor.

While the inheritor could have public override Branch Add(string name, string committish) now they cannot because the method is defined elsewhere an in a non-override-able way (unless the language has provided functionality that I'm unaware of). This reduces the utility of the library and makes me sad.

I am a little concerned about calling partial class implementations xxxExtensions when they are not actually extensions, but partial implementations. I think the CLR guys do this best when they use the ClassName.FunctionalityGroup.cs naming convention. They can then group all of sub-files under a single entry in the Solution Explorer though XML hackery - which makes finding stuff actually easier.

So while this is cleaner, I sadly feel I need to 👎 the change as is. 😞

@ethomson
Copy link
Member

I've never been a fan of all overloads functions in one place...

Why extensions, then, and not partial classes?

@carlosmn
Copy link
Member

If it is about separating the implementation into multiple files so we have the core plus convenience, functions, I agree that partial classes sound like a much better match. Extension methods are made so you can inject methods into external code, but we own all of libgit2sharp; partial classes would allow for the code to be split across files but still clearly signal that it's our code.

@Therzok
Copy link
Member

Therzok commented Jun 15, 2015

While the inheritor could have public override Branch Add(string name, string committish) now they cannot

Thing is, why would you have different behaviours between string commitish and Branch b, since both resolve to the same thing? Only one method should be virtual, possibly the one which is called into from all extensions and don't allow overriding the public function, but add a virtual protected OnAdd(param1 param2).

Why extensions, then, and not partial classes?

That's even better, imo, I'm up for this.

@whoisj
Copy link

whoisj commented Jun 15, 2015

@carlosmn in many C# projects, extension methods are also used to implement methods which cannot be overridden as well. Not that I agree with that, but it does enable the creation of partially sealed classes.

That said, I don't think that this is the point of this PR and I full agree that partial classes are likely a better solution.

@whoisj
Copy link

whoisj commented Jun 15, 2015

Thing is, why would you have different behaviours between string commitish and Branch b, since both resolve to the same thing? Only one method should be virtual, possibly the one which is called into from all extensions and don't allow overriding the public function, but add a virtual protected OnAdd(param1 param2).

Why not? What if a service does OI logging and they wanted to hook one of the methods and add a logging event in it? What if an implementation wanted to prevent the use of commitish and wanted to replaced one of the methods with a throw new NotImplementedException to make sure none of their devs used it?

We cannot pretend to know how the library will be used. We can only provide the most useful library possible.

@nulltoken
Copy link
Member Author

So partial classes would be a 👍?

@whoisj
Copy link

whoisj commented Jun 15, 2015

So partial classes would be a 👍?

I do believe that is the consensus. 😄

@dahlbyk
Copy link
Member

dahlbyk commented Jun 16, 2015

I don't see much point in breaking out partial classes, TBH.

@ethomson
Copy link
Member

@dahlbyk Meaning everything in one file, or you prefer the status quo using extensions?

@dahlbyk
Copy link
Member

dahlbyk commented Jun 16, 2015

I haven't struggled with the extensions, personally, so I lean toward:

  1. Members to implement interfaces (duh).
  2. Members for unique "full" method signatures (typically the ones with options).
  3. Extensions for convenience overloads with reasonable defaults.

I'm not sure how much I buy the "what if we need to inherit?" argument because we return concrete implementations throughout the code. Outside of testing I'm not sure how it would ever be useful to override our virtual members.

@shiftkey
Copy link
Contributor

Why extensions, then, and not partial classes?

I always come back to the canonical use case for partial classes - codegen. Beyond that I'm generally skeptical about it's value - perhaps there's some underlying issue which is being masked by extracting partial classes? Maintainability? Complexity?

Extension methods are okay, but again, my favourite use case for them is "for types you don't own". Beyond that, I'd push back and question what problem we're trying to solve here.

@nulltoken
Copy link
Member Author

So partial classes would be a 👍?

I do believe that is the consensus. 😄

Indeed, fastest consensus reach ever. 😜

@nulltoken
Copy link
Member Author

As it looks like I'm the only one who dislikes overloads living next to the concrete implementation, how about just getting rid of the xxxExtensions.cs files and moving everything from them back in xxx.cs files?

@dahlbyk
Copy link
Member

dahlbyk commented Jun 16, 2015

I would be fine with folding xxxExtensions into the "parent" class with the possible exception of classes that implement interfaces. Then again, our interfaces really aren't meant to be implemented externally, so it may not matter if it would be tedious to reimplement them.

@nulltoken
Copy link
Member Author

@dahlbyk Good point regarding the interfaces.

I would be fine with folding xxxExtensions into the "parent" class

Do anyone oppose to this?

@nulltoken
Copy link
Member Author

I've started to work along @dahlbyk's proposal. How does it look?

I've also taken the opportunity to surreptitiously introduce some breaking changes.

@whoisj
Copy link

whoisj commented Jun 17, 2015

Seems reasonable to me. I do prefer concrete implementations to extensions. 👍

@dahlbyk
Copy link
Member

dahlbyk commented Jun 17, 2015

Convert * into a property

Are these adjustments worth a breaking change? Or do we not really care until stabilization is complete (I'm out of the loop on those discussions)?

@nulltoken
Copy link
Member Author

I think this is now done. Only remaining points are some submodule status related extensions (hence the failing build). They actually look like unused, which is weird. What should we do with them?

/cc @dahlbyk @jamill

@whoisj
Copy link

whoisj commented Jun 18, 2015

They actually look like unused, which is weird. What should we do with them?

I'd like to keep them as I have plans to use, at least some of, them.

@dahlbyk
Copy link
Member

dahlbyk commented Jun 18, 2015

What should we do with them?

Add tests for them, exclude enum extensions in meta test?

@nulltoken
Copy link
Member Author

Add tests for them, exclude enum extensions in meta test?

I'm not sure I'd be able to add interesting tests (other than copying the implementation).

How about I mark, for now, the enum as internal and let @whoisj add the tests when he actually needs the enum? 😈

@whoisj
Copy link

whoisj commented Jun 18, 2015

How about I mark, for now, the enum as internal and let @whoisj add the tests when he actually needs the enum? 😈

That should be fine. It'll be a few weeks before I start on my submodule stuff - no point in using your time now for something I'll need only then. 😊

@nulltoken
Copy link
Member Author

How about I mark, for now, the enum as internal

That should be fine.

Done. Ready for final review.

no point in using your time now for something I'll need only then

@whoisj 😍

@jamill
Copy link
Member

jamill commented Jun 18, 2015

If someone actually uses this API they will be broken when we remove it. While we are pretty good about testing APIs, surely this isn't the only one missing test coverage, so I don't know if missing test coverage is reason enough to remove it.

@nulltoken nulltoken changed the title [WIP] Convert overloads as extension methods Remove extension methods Jun 18, 2015
@nulltoken
Copy link
Member Author

@jamill It's not a definitive removal. It'll be reintroduced as soon-ish by @whoisj.

@nulltoken
Copy link
Member Author

Beside we can't publish anything until #1091 is fixed.

@nulltoken
Copy link
Member Author

@jamill Regarding code coverage, you're right. I've logged #1106 to not forget about it

@nulltoken
Copy link
Member Author

@dahlbyk 💎 ‼️

@dahlbyk
Copy link
Member

dahlbyk commented Jun 18, 2015

Pushed a rebound, feel free to discard. I don't see a reason to drop these methods for lack of test coverage in a PR about removing invalid extension methods. If extensions on an enum are considered valid (and they should be, IMO), then we might as well test accordingly.

@nulltoken
Copy link
Member Author

Pushed a rebound, feel free to discard.

I won't. Your approach is far better. Thanks for this!

@nulltoken nulltoken force-pushed the ntk/overloads branch 2 times, most recently from bdfa49d to 025b273 Compare June 18, 2015 22:02
nulltoken added a commit that referenced this pull request Jun 19, 2015
@nulltoken nulltoken merged commit 70d0c3b into vNext Jun 19, 2015
@nulltoken nulltoken deleted the ntk/overloads branch June 19, 2015 09:06
@nulltoken nulltoken added this to the v0.22 milestone Jun 19, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants