Skip to content
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

Return: x → [x] #615

Closed
MitchBodmer opened this issue Oct 18, 2019 · 11 comments
Closed

Return: x → [x] #615

MitchBodmer opened this issue Oct 18, 2019 · 11 comments
Assignees
Milestone

Comments

@MitchBodmer
Copy link
Contributor

I'd like an extension method that takes an object and converts it into a single element as discussed here.

It's not linq per se, but it seems to fit nicely with the spirit of this library. I'd be happy to provide a PR if you think it fits.

@atifaziz
Copy link
Member

I can see adding this as a static method on MoreEnumerable (Singleton or Unit would be a good names) but it would be against the spirit/scope of this library as an extension method on any type T. Given that Enumerable.Repeat("foobar", 1) already exists in LINQ to the same effect, we would want something that's a little smarter (worth the trouble then) and so the sequence of one returned by such a method should be an IEnumerable<T> that also implements IReadOnlyCollection<T>, ICollection<T>, IReadOnlyList<T> and IList<T> to trigger optimisations.

If you think that still aligns with what you had in mind then a PR would be most welcome.

@MitchBodmer
Copy link
Contributor Author

That would certainly still be nice to have. I'd prefer an extension method on any type personally, but I know there isn't anything like that in this library now. Are you worried that something like that opens a little Pandora’s box of features in this vein?

As far as naming is concerned:

Singleton, to me, suggests a type that can only be instantiated once, not a single element enumerable.

Unit, to me, suggests the functional unit type, which does not hold a value.

Looking around I might go with either Just (taking inspiration from reactivex and Option/Maybe types), Return (taking inspiration from .NET's reactive extensions impementation), or Yield (which I think works a lot better as an extension method).

I think my vote would be for Just. It seems to be the most fluent and easily understood.

@atifaziz
Copy link
Member

Are you worried that something like that opens a little Pandora’s box of features in this vein?

Yes, that's a big part of it besides being out of scope and having the potential to introduce conflicts. If someone wants an extension method, it's a one-liner to add to their project locally.

Singleton, to me, suggests a type that can only be instantiated once, not a single element enumerable.

That's singleton as an OOP design pattern. I suggested Singleton to borrow from Seq.singleton in F# that does exactly the same.

Unit, to me, suggests the functional unit type, which does not hold a value.

I suggested Unit because (like Return) that's what type converters are typically named in the world of monads.

I think my vote would be for Just. It seems to be the most fluent and easily understood.

While Just is nice and short, it seems to unnecessarily overlap with options. I would urge you to re-consider taking Return from Rx (Reactive Extensions for .NET) as a good parallel or (preferably) Singleton from F#'s Seq. If you insist on Just, I can let it pass as a fair compromise. 😉

@MitchBodmer
Copy link
Contributor Author

No insistence here! I'm totally fine with Return.

@atifaziz
Copy link
Member

Return it is then.

I'd be happy to provide a PR

I'm assuming you'll be submitting a PR next? I am getting the next version (3.3) ready to ship soon. I was hoping for yesterday but I missed that deadline as other things took priority. I have now deferred the release to Monday of the week after next. No one's holding a gun to these dates but it gives a goal and some focus. Do you think we can get this into that release or would you need more time?

@atifaziz atifaziz changed the title Yield extension? Return: x → [x] Oct 26, 2019
@MitchBodmer
Copy link
Contributor Author

I think I can manage that. Let me give it a go and we'll see how far off the mark the PR is.

@atifaziz
Copy link
Member

Awesome & looking forward.

@atifaziz atifaziz added this to the 3.3.0 milestone Oct 28, 2019
@MitchBodmer
Copy link
Contributor Author

Hey can you elaborate a little on what you meant by "to trigger optimizations"? Which optimizations are we trying to get specifically?

@atifaziz
Copy link
Member

Sure. What I mean is that if someone composes with First, Last, Count and so forth, then these will do a runtime type check whether the IEnumerable<> is in fact a collection or a list. If it's a collection then something like Count can just probe the Count property instead of iterating the sequence to do the actual counting. Likewise, First and Last can use the indexer directly if the sequence happens to be a list. Such optimisation avoid an allocation for the enumerator if the sequence doesn't need iterating and also operate faster. So by implementing the right interfaces that make sense, you are triggering optimisations built into certain methods.

Have a look at commits with the word “optimize” for examples how some of the extensions in MoreLINQ are optimised under certain conditions (including type checks), with the most recent one just being from a couple of days ago.

@MitchBodmer
Copy link
Contributor Author

Gotcha.

So is there any reason not to have this method return an IEnumerable that is actually just a single element List? That seems to be the simplest way of satisfying the requirements for the optimizations.

@atifaziz
Copy link
Member

atifaziz commented Nov 1, 2019

So is there any reason not to have this method return an IEnumerable that is actually just a single element List? That seems to be the simplest way of satisfying the requirements for the optimizations.

Absolutely except it has to be sufficiently different than just conjuring up an an array of one element (e.g. new[] { 42 }) or using Enumerable.Repeat(x, 1) to warrant adding here. An array satisfies all goals except it can be cast down and modified, which bothers some people. Enumerable.Repeat always yields so will cause enumerator allocations in the worst case. The IEnumerable<> that Return will give back should be backed by a read-only list of one element that implements IReadOnlyCollection<T>, ICollection<T>, IReadOnlyList<T> and IList<T>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants