-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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 into(T::Type, iterable) -> collection::T #36537
base: master
Are you sure you want to change the base?
Conversation
This is required for inferring `Fix1(convert, Int)(x)`.
Each container may choose a specific widening strategy.
How about making this a two-argument method of |
One problem is that That said, I'm not a fan of adding a new function, nor of the |
Yes, that's the biggest reason why we can't use
We can't use this when
I extensively discussed why constructor and |
Sorry, I hadn't seen the issue as I was completely drowned in the previous weeks. But it's not unusual in my experience to get comments only when making the PR... I think I'd prefer calling this Also, maybe the fallback could be defined as |
FWIW, |
@test @inferred(into(Tuple{}, 1:0)) === () | ||
@test @inferred(into(NTuple{1,Int}, [10])) === (10,) | ||
@test @inferred(into(NTuple{2,Int}, [10, 20])) === (10, 20) | ||
@test @inferred(into(NTuple{2}, [10, 20])) === (10, 20) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the inferrability here
I really like this proposal; I think the functionality is clear, and immediately seems more flexible/useful than just For a custom array type, it wasn't clear to me what I might need to do in order for things to "just work" for my array type? I think it'd be helpful to have some docs/walk-through of how to implement for a custom array type (and do so correctly). I guess there's not really a good "default implementation" for AbstractArray? |
Is there really a need to separate dispatch here? What is the use-case in specializing |
@nalimilan Yes, I agree. I should have clarified in the OP that the motivation and background are discussed elsewhere.
I think these are reasonable alternatives and I'm open to rename.
I think the problem is that I've struggled about what to do (or don't) with the fallback. I think the question is if it is better to enforce the invariance Line 88 in 43ac07d
I think it's valuable that you can depend on the invariance like
@quinnj Actually, this interface is opt-in as I couldn't think of any better way to ensure the invariances you'd want from this interface. For example, if we have the fallback
@mbauman For example, we can make function __from__(T, it::EachLine)
try
return __into__(T, it)
finally
it.ondone()
end
end It's also useful for something like (If we had an extensible mutate-or-widen API like
I think ambiguity is going to get in our way for this. Something like In general, I think we should decouple surface/call API and overload API whenever makes sense. This way, we can do more pre/post processing like error checks and also impose more invariance of the API (like |
Ah, right. These things are incredibly tricky...
Do you think there can be situations where this invariance cannot be satisfied? I wouldn't have thought so (in the worst case, conversion of source elements fails, but that's expected). |
I was rather worried about the cases where the function accidentally returns and the caller gets a collection of a wrong type. This is very easy to happen if we use something based on Perhaps more illustrative points are other properties like " |
I would prefer that the function name started with (The fact that other languages call their type-conversion function It's not clear to me why we need two overload entry points. If package A defines the collection, and package B defines the iterable, then whichever package imports both A and B defines the |
Not that Clojure uses
Do you think it's possible to implement I think the double-dispatch is required when the "data source" want to take control in general. For example, I'd like to use this for |
I like I see your point with the double dispatch… |
Just call it |
How about |
I still prefer |
Yeah, I like itr |> Map(f) |> Filter(p) |> into(DataFrame) |
It does seem like the best to me given that |
|
In that case |
I disagree. I don't think it's super readable (makes me think of some kind of spanish/french verb conjugation). And I think the underscore version is uglier, though more clear. |
Bump; recently ran into unexpected inconsistency between |
Lately, I started thinking that I should create a package for this since I feel the double dispatch system is still rather incomplete. The dispatch pipeline would be much more powerful if we had a standard mutate-or-widen collection interface (i.e., what I call |
Yeah, having this as a package would be great to play around with. |
close #36288
This PR implements the API I proposed in #36288. Here is the (refined) API I ended up implementing in this PR. Quoting the docstrings:
Surface API
Construct a new
collection
of typeT
that contains the elements initerable
. Ifiterable
is also a container, it acts as a shallow-copy.If
T
haseltype
,keytype
, orvaltype
information, all elements incollection
are converted to the destination type to guarantee the constraintcollection isa T
.If
T
has size or length information (e.g.,NTuple
andStaticArray
), providingcollection
with unmatched size or length throws an error.Unary form
into(T::Type)
returns a callableiterable -> into(T, iterable)
.Extended help
Example
into
takes care of the conversion of storage and element types:into
acts like a shallow copy:into
always treats inputiterable
as a collection:into(T)
returns a functioniterable -> into(T, iterable)
which is appropriate for using with|>
:Implementation
The owner of the type of
iterable
should implement__from__
. The owner of the output typeT
should implement__into__
. If it is desirable to apply pre- and/or post-processing, the owner of the output typeT
may implementinto
.Overload API
Overload-only API for providing the implementation for
into(T, iterable)
.To avoid method ambiguities,
__into__
should be implemented only by the owner ofT
and__from__
should be implemented only by the owner oftypeof(iterable)
. The owner ofT
(resp.typeof(iterable)
) may choose to allowtypeof(iterable)
(resp.T
) to overload__into__
(resp.__from__
) by documenting specific type bounds forT
(resp.typeof(iterable)
).into(T, iterable)
calls__from__(T, iterable)
which in turn by default calls__into__(T, iterable)
.Implementation
If
T
is a subtype ofAbstractArray
,must hold where
collect′
is defined asIf
iterable
is a stateful iterator,collect
insidecollect′
is "run" as if the world is rolled back to the state just before callinginto
.If the collections of type
T
do not support duplicates,issubset
may be used instead ofisequal
. In particular, subtypes ofAbstractDict
andAbstractSet
must satisfy the above equality withissubset
.If the collections of type
T
do not maintain insertion order,issetequal
may be used instead ofisequal
.