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
Add Cast<T> and CastFrom<TDerived> to ImmutableArray<T> #13980
Comments
Excellent write-up. That makes total sense to me. +1 |
👍
The conversion's success has nothing to do with the types of elements in the array, and everything to do with how the array itself was created. A |
I spent probably a good five minutes on that sentence and couldn't find anything I was truly happy with (that didn't expand into a mini version of the C# spec). :( |
In general I like the idea and I support the functionality but I'm a little interested to see what others think about the names. We don't have any other methods in the framework called CastUp or CastDown. Perhaps we could call CastUp just Cast and CastDown CastDynamic or something along those lines. |
I don't think there are names we could recycle. Personally, I actually like the proposed names. |
|
I made an update to the proposal. @stephentoub pointed out that the way I had
The method was changed to reflect this and rename to For the second method I personally prefer |
That makes sense. I agree that in that |
@terrajobst updated |
As a developer trying to use these APIs how am I to figure out that Another question you are proposing we remove a public API what impact will that have? Have we shipped a stable version with that API? |
@weshaggard the term cast is generally associated with a type conversion, not an allocation. Neither of these APIs is allocating, it is just doing a type conversion under the hood. The difference between the methods is @nguerrera or @AArnott would have to comment on whether or not we've shipped with that API public before. |
@jaredpar sorry I miss understood the allocation part after re-reading your proposal I think I confused it with the comparison to the other Create methods which allocate. In your code example what happens if people do this:
That seems to me like the most natural thing for someone to do. If that isn't substantially worse than calling the static |
@weshaggard the code will end up producing the same result with an additional type check. The reason for adding the extra concept is that this type check can be significant in tight loops. Roslyn for example regularly executes this exact pattern in the parser:
Profiles showed that the type check in this conversion was taking up a significant portion of parse time. Moving to the non-type checking version was a clear win (and one that we simply cannot regress on). The awkward consumption of the existing We felt it was enough of a win that it should just be in the core API. |
Thanks for the explanation I'm good with the additions. I would like to get clarification from @nguerrera and @AArnott before we remove the one Create method however. |
In the previous API Review meeting, I think it was mentioned that we had not shipped a stable version of ImmutableArray yet, and were free to make these changes. Note that we just renamed ReverseContents to Reverse with dotnet/corefx#399, so we are already making changes along these lines. |
ImmutableArray itself has never shipped in a stable package, so we're good On Mon, Jan 12, 2015, 10:32 PM Matt Ellis notifications@github.com wrote:
|
Yes, we can still make breaking changes to ImmutableArray, but we had said that we'd keep them to a minimum if at all possible. I do see a few uses of |
One comment, the type parameter for Cast should be probably just Cast, to be consistent with Linq, and to indicate that it can go both up and down. |
Won't Cast hide the lynq extension method? Their behaviors, return types On Tue, Jan 13, 2015, 11:17 AM David Kean notifications@github.com wrote:
|
Return type differences are fine - it's common to provide strongly typed versions of enumerable extensions. How will their behaviors differ? |
@davkean the LINQ Animal a = new Dog();
var array = ImmutableArray.Create(a); // Creates a Animal[]
Enumerable.Cast<Dog>(array); // Successfully returns IEnumerable<Dog>
array.Cast<Dog>(); // Fail: can't convert Animal[] -> Dog[] C# binding rules will cause |
|
|
@AArnott |
What's the behavior when the cast doesn't succeed? Can you call this out in the spec? |
@davkean from the spec
Is there something else you wanted to say in addition to that? |
Which exception, InvalidCastException? |
@davkean it throws whatever the array conversion would throw. |
This is the PR that corresponds with API request issue #400. The issue has the full details of this change but in summary Adds ImmutableArray<T>.CastUp<TDerived> static method. This allows the caller to convert from an immutable array of derived elements to parent elements (ex: string to object). This conversion is statically verifiable and has no allocation or dynamic type check. Adds the ImmutableArray.CastArray<TOther> method. This method is the immutable array equivalent of casting a standard CLR array to a related array type. http://msdn.microsoft.com/en-us/library/aa664572%28v=vs.71%29.aspx If the conversion fails an InvalidCastException will be thrown.
We've reviewed this proposal and we're fine with this approach. We've some concerns around the naming but this can be reviewed on the PR. |
Fixed via dbfb49b |
The
ImmutableArray<T>
type should have easier to find and use APIs for converting between related array element types.Rationale and Usage
The
ImmutableArray<T>
type is meant to be as close as possible toT[]
in functionality without the possibility of mutation. One area where it is lacking or at least harder to discover is type conversions.With arrays it is possible to convert
T[]
toU[]
whenT
inherits fromU
. This conversion is implicit and requires no dynamic type checking.The equivalent code for
ImmutableArray<T>
is less intuitive:There are a few issues with this approach:
As
,Cast
, etc ...). They will not stumble upon this particular method unless they go through every overload ofCreate
and read the documentation.Create
which implies an allocation. All otherImmutable.Create
methods indeed allocate. In this case though no allocation occurs, it simply repackages the underlying array in a new struct.Additonally the API is lacking in functionality. It has a static up cast member (
ImmutableArary.Create<T, TDerived>
), a dynamic type check member (ImmutableArray<T>.As
) but no dynamic down cast member. Normal array code like the following has no direct mapping inImmutableArray<T>
Proposed API
The first part of the proposal is to delete
ImmutableArray.Create<T, TDerived>
. The method name does not line up with its functionality and placing it onImmutableArray
makes it impossible to take advantage of type inference.The following methods will be added to
ImmutableArray<T>
:Putting the methods here both increases their discoverability and allows us to take advantage of type inference. The
T
value is always known hence the developer only has to specify the target type (as they do with standard arrays). The original sample above becomes:Details
CastFrom
will have the same functionality asImmutableArray::Create
. It will be non-allocating and not generate any runtime type checks. The constraints on the method are sufficient for the CLR to guarantee the conversion will succeed.Cast
will be non-allocating but will have a dynamic type check. If that type check fails an exception will be generated (in the same manner as a normal C# array conversion).The text was updated successfully, but these errors were encountered: