-
-
Save ilkerde/864508 to your computer and use it in GitHub Desktop.
public IEnumerable<Answer> GetAll() | |
{ | |
List<Answer> answers = GetAnswers(); | |
return answers; | |
} |
@lanwin: thank you for your detailed reply. appreciate it! i totally understand your point about the "unknowing" or "careless" usage of List instead of IEnumerable. However, as I mentioned in one of my previous comments, my point here is not about (im)mutability.
The background for my "return type" question is quite specific. GetAnswers already memorizes the complete (finite) set. If you do not feel comfortable with the word "memorize", maybe "materialize" or "copy" will work. Basically, GetAnswers "stores" the complete set in a List (in memory). However, the outer function (GetAll) exposes an IEnumerable. That is, it effectively downcasts the type, rendering the result to a forward-only and immutable representation of the set in question. For now, put the mutability thing aside. I might just have used Anwer[] as return type for GetAnswers as well:
public IEnumerable<Answer> GetAll()
{
Answer[] answers = GetAnswers();
return answers;
}
Now everything is readonly and immutable. Now, having left this mutability (readonly / modifiable) aspect behind us, the downcast as well as the memorization aspect remains. The memorization aspect is what I wanted to stress with my question.
One last note: I do have a very strong opinion about this specific scenario as well as the general usage of IEnumerable as return type for finite sets. However, I won't express my opinion (yet), since I don't want to influence anyone with my perspective.
It was intentional to phrase my question as an open question. Hoewever, since almost anyone looking at the code concentrates on readonlyness and information hiding, i finally decided to rephrase my question and be more specific:
would you rather expose or hide the memorization of the set of answers?
I would hide the "memorization" of the set of answers with a return of IEnumerable instead of Answers[]. Let your caller decide what he want. (IoC, SRC, SoC) -m2c
IMHO the caller should not be bothered by "memorization" aspect. He should not care. IEnumerable could lead the caller to think about "memorization" aspect. List or even IList are a bit to heavy (overhead) for a set of answers IMO. So give Collection and ReadOnlyCollection a thougt. I personally often use IEnumerable for public service interfaces despite it's not recommended by many people. -m2c
Hi,
first of all I wouldn't return IEnumerable here. The materialized vs. lazy question is very important. You have the same discussion in Rx land with "hot" and "cold" observables (http://channel9.msdn.com/Blogs/J.Van.Gogh/Rx-API-in-depth-Hot-and-Cold-observables). IMHO you should reflect this in your signature.
But if you use List or Array you are destroying the whole idea. I would consider a immutable list here.
Immutability is even stronger than the materialized view.
Materialized statement: "I calculated all values for you. Feel free to iterate over the collection as often as you like"
Immutable statement: "I calculated all values for you and they will not change in the future. Feel free to iterate over the collection as often as you like and feel free to store additional information (like checksums)."
That said, there is another interesting point here. Consider the following function:
public IEnumerable<Answer> FilterImportantAnswers(IEnumerable<Answer> allAnswers)
{
return answers.Where(a => a.Important);
}
I often struggle about such functions in .NET, because it is effectively removing type information, like here:
IEnumerable<Answer> answers = FilterImportantAnswers(myImmutableListOfAnswers);
After applying this filter I lose my concrete type and everything is just IEnumerable.
In Haskell one could use type classes to solve this problem. In C# pseudo code something similar could look like this:
public T<Answer> FilterImportantAnswers(T<Answer> allAnswers) where T allows Where
{
return answers.Where(a => a.Important);
}
ImmutableList<Answer> answers = FilterImportantAnswers(myImmutableListOfAnswers);
Regards,
Steffen
Edit:
Sorry. Immutability is not stronger as IEnumerable shows. But they play together.
Materialized statement: "I calculated all values for you. Feel free to iterate over the collection as often as you like"
Immutable and materialized statement: "I calculated all values for you and they will not change in the future. Feel free to iterate over the collection as often as you like and feel free to store additional information (like checksums)."
@steffen: Nice aspect. Unfortunately we can not do
public T FilterImportantAnswers(T allAnswers) where T allows Where
in C#. :-(
That's why I wrote "could" ;-)
@steffen: Sure. I'm sorry that we can't do that in C#. But your answer is a good answer for me "When you should return IEnumerable and when a type with the context of a "materialized" scope." Thx.
@mike: That's not only a problem of C#. It seems this is general problem in .NET generics.
@steffen: Yes, you're totally right.
There is another point. If you return IEnumerable instead of Array or List you are disabling fast indexed access. Why would you do this?
In general: I don't see any value in returning a base class if you could return the concrete class. But maybe I am wrong.
If you want immutability then just use an immutable data structure.
@codefromground thanks for your thoughts. appreciate it. i truly hope that we can dive into topics as this one while having a nice espresso at your site ;) Regarding the ReadonlyCollection: I'm really sorry that my initial example utilized a List. It distracted too much from what i wanted to stress. The second example (using Answer[]) fits more to what i wanted to have opinions for.
@forki Thanks indeed for your in-depth and thoughtful comments.
I do believe that I would have never achieved to express the importance of materialization (and even more, preserving the materialization information by type signature) as you did in your comment.
At this point, I'd like to thank all of you for lending your time and brain for my little question. It was very valuable and insightful.
Totally agree @lanwin. This is the reason for questions. Know the coder the functionality of IEnumerable or not. When I know I can hide list functionality to external callers with the special of lazy evaluation.