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

RFC: into(T::Type, iterable) -> collection::T #36288

Open
tkf opened this issue Jun 15, 2020 · 1 comment · May be fixed by #36537
Open

RFC: into(T::Type, iterable) -> collection::T #36288

tkf opened this issue Jun 15, 2020 · 1 comment · May be fixed by #36537
Labels
collections Data structures holding multiple items, e.g. sets design Design of APIs or of the language itself feature Indicates new feature / enhancement requests

Comments

@tkf
Copy link
Member

tkf commented Jun 15, 2020

tl;dr Can we have an API (say) into(T::Type, iterable) -> collection::T for creating a collection of type T from an iterable?

Problem

Given an arbitrary iterable and arbitrary container type, there is no consistent API to construct the container. The closest thing probably is to call the constructor. Indeed, that's what the documentation recommends

if T is a mutable collection type then T(x) should always make a new collection (copying elements from x).

--- https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Mutable-collections-1

However, even things like Vector(1 + x for x in 1:10) or Vector(Dict(:a => 1)) do not work (ref #16029). For Vector, we can use collect but having arbitrary factory function for each custom container type is not great.

Furthermore, this recommendation is not always reasonable. For example, if you want to implement own vec with

struct VectorView{T,P <: AbstractArray{T}} <: AbstractVector{T}
    parent::P
end

you'd want to VectorView(array) to not copy the input array. It is reasonable to expect constructors to do only minimum amount of work, especially for "wrapper" types. For example, StructArray(a = vector) doesn't copy the input vector (although it's not of the form T(x)).

Another problem is that constructors usually have a particular semantics. For example:

All of these points suggest that it would be nice to have an entry point for constructing a container given its type and the input iterable, separated from the constructor.

For example, StaticArrays has sacollect(::Type{<:StaticArray}, itr) JuliaArrays/StaticArrays.jl#792 for collecting an iterable as a given type. It'd be great to have a uniform interface so that it is possible to overload.

Proposal

API

into(T::Type, iterable) -> collection::T

Construct a new collection of type T that contains the elements in iterable. If iterable is also a container, it acts as a shallow-copy.

If T has eltype, keytype, or valtype information, all elements in collection are converted to the destination type. Otherwise, if IteratorEltype(collection) is HasEltype() and type T can specify element type in the type domain, eltype(typeof(new)) == eltype(typeof(collection)) holds.

If T has size or length information (e.g., StaticArray), providing collection with unmatched size or length throws an error.

Default implementation

It is probably OK for many cases if we use the fallback implementation

into(T::Type, collection) = T(collection)

Alternatively, a safer implementation is:

into(T::Type, collection) = T(collect(collection))

Naming bikeshedding

The name into is something I stole from Clojure https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/into

In Python, I see $Class.from_$thing(thing) classmethod pattern. Translating this to Julia, from(T, iterable) can also be a reasonable choice?

Some more random alternatives:

collect_to(T, iterable)
collectto(T, iterable)
copyto(T, iterable)
copyas(T, iterable)
makeof(T, iterable)
pour(T, iterable)
funnel(T, iterable)

Related discussions

@tkf tkf added collections Data structures holding multiple items, e.g. sets design Design of APIs or of the language itself labels Jun 15, 2020
@harryscholes
Copy link
Contributor

Rust also uses into methods for conversion

https://doc.rust-lang.org/std/convert/trait.Into.html

@nsajko nsajko added the feature Indicates new feature / enhancement requests label Apr 28, 2024
nsajko added a commit to JuliaArrays/FixedSizeArrays.jl that referenced this issue May 1, 2024
* introduce function `collect_as` for construction from an iterator

Makes constructing `FixedSizeArray`s more convenient!

Inspired by
JuliaLang/julia#36288

This currently ignores `Base.IteratorElType`, xref
https://discourse.julialang.org/t/i-dont-get-base-iteratoreltype/113604

The allocations in some code paths are probably excessive/could be
optimized. But I guess this is good for a start.

Fixes #20

* also test an iterator with `BigInt`-valued `size` and `length`

* remove the premature optimization for `AbstractArray`

* improve tests

* add to the Readme

* whitespace/formatting fix

* delete two useless `nothing` lines

One of these wasn't being recorded by code coverage (another Julia
coverage bug, I guess).

* simplify a bit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
collections Data structures holding multiple items, e.g. sets design Design of APIs or of the language itself feature Indicates new feature / enhancement requests
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants