-
Notifications
You must be signed in to change notification settings - Fork 25
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
Table()
throws - implement zero column tables
#55
Comments
Thanks @tkf! Not a bad idea. Yes, this is a known issue. It's actually slightly more complicated than you'd think, since a zero-column table should be able to iterate an arbitray number of empty named-tuples. Just setting it to "empty" isn't a good option (it would anger the "Third Manifesto" gods, for one). I'm thinking the constructor should check the arrays are the same length and we should store the |
Naively thinking, I thought Table{Union{}, 1, NamedTuple{(), Tuple{}}}(NamedTuple()) works (although Table{Union{}, N}() where N = Table{Union{}, N, NamedTuple{(), Tuple{}}}(NamedTuple()) ? I think this matches with the idea that "the constructor should check the arrays are the same length" since
Is it a relational algebra thing? It somewhat resembles the empty intersection/vacuous truth but I can't see the connection. |
You can't do much more with it except Maybe we want a
Kind of, I guess... there's an isomorphism between the number of things in a bag and natural numbers. For set theory, |
Table()
throwsTable()
throws - implement zero column tables
Maybe we should avoid
This could pessimize a zero-column typed table of static arrays. A corner case, to be sure, but... I'm now thinking the zero column form could be The method specializations of that make a fascinating form, where a |
Oh, I forgot about
Actually, I do. In Transducers.jl, foldl(push!!, xs, init=Union{}[]) This implements mutate-or-widen strategy because Writing this, I just realized that how vcat(empty_table, Table(a=[1])) == Table(a=[1]) (or something similar as a wrapper function of
I think I want julia> promote_type(Union{}, typeof((a=1,)))
NamedTuple{(:a,),Tuple{Int64}}
julia> promote_type(typeof(NamedTuple()), typeof((a=1,)))
NamedTuple so, the logic inside
Is As for the analysis of |
Reading a bit about relational algebra (BTW, thanks for the remark on joining with the empty relation), I'm more confident that I need Having said that, I think a bigger question is: what should be in the minimal sink-oriented tables interface? I've been thinking it would be:
Instead, maybe we should have the singleton container constructor like |
I think I explained my implementation details too much. A simple question is: how do you write a function for materializing a |
Sorry, @tkf, I've been following along but haven't been able to reply yet.
That is a great question. At the moment here we are relying on the element type being known, and It's worth keeping in mind that there's no part of the But yes, in general I can see we should support both zero-element
Let me ask a counter-question: what is the miminal sink-oriented array interface? |
Let me first answer a related simpler question: what is the miminal sink-oriented collection interface. So I'll forget about arrays with Approach 1:
|
Not sure if it's of interest, but there is code in Tables.jl that essentially builds up a "Table" (more specifically, a NamedTuple of Vectors) from an arbitrary property-accessible iterator, with or without known length (https://github.com/JuliaData/Tables.jl/blob/master/src/fallbacks.jl#L146). We essentially start each column out as |
@quinnj Hi, thanks for the comment. I know people implement widening-based collect-like functions in various places (Tables.jl, StructArrays.jl, ...) but it is rather sad that there is no canonical API for this. It would be great if there is a base package ( |
Regarding your two options - we need to support the case where the output container is empty with full type predictability. Are you falling back on inference whenever
Yes, which is precisely why I was asking my question :) In this case, for Dictionaries.jl, where I am trying to have proper interfaces for insertability, mutability, immutability, etc, and the next problem to solve is "factories" - help welcome on interface ideas.. (After that, Jacob, I want to make a dictionary-like table, as opposed to these array-like tables, but they need to iterate rows not key-value pairs for it to be a Tables.jl table, hence the need for a new dictionaries interface). I've found there's a class of containers where |
I agree. We can probably even say that the class of container is defined by the minimal requirements (as a sink). Something like:
|
By the way, I decided to go with "fake/lazy empty table" ( |
Ok. So what do you do when the output really is empty? |
This is related to your comment in #56 (comment):
I understand that that not computing type by hand is the best practice (the worst example being But, I believe a container with (The reason why I could still implement something like |
on a related note, |
Kind of. In TypedTables a The difference with dataframes is that a
I'm not sure - here (and in Dictionaries.jl) I've tried to keep indexing and iteration semantics in line with each other. The DataFrames approach is more pragmatic and practical and I wouldn't argue that |
I tried to create an empty table by
Table()
but it failed atTypedTables.jl/src/TypedTables.jl
Line 23 in fc1247a
because
n
is undefined.My motivation is to use this with
push!!
so thatThis, in turn, can be used to define "
collect
" with the mutate-or-widen idiom. This came up in JuliaFolds/Transducers.jl#73 (comment)FYI, it would have caught by
Test.detect_unbound_args
:Why not run
@test detect_unbound_args(TypedTables) == []
in the test? See also https://github.com/tkf/Aqua.jlThe text was updated successfully, but these errors were encountered: