# \[ANN\] Tables.jl 1.0 Release

**URL:** <https://discourse.julialang.org/t/ann-tables-jl-1-0-release/34505>\
**Category:** Data\
**Created:** [February 12, 2020, 7:32am UTC](https://discourse.julialang.org/t/ann-tables-jl-1-0-release/34505 "2020-02-12T07:32:47Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [February 12, 2020, 7:32am UTC](https://discourse.julialang.org/t/ann-tables-jl-1-0-release/34505/1 "2020-02-12T07:32:47Z")

</div>

Hello all,

A new [1.0 release](https://github.com/JuliaData/Tables.jl/releases) was just registered in the General registry for the Tables.jl package.

The API has matured well over the last 1.5 years (since 2018 JuliaCon hackathon!), and we felt like it was time for an official 1.0 release. Highlights for 1.0 include:

- A _ **ton** _ of new [documentation](https://juliadata.github.io/Tables.jl/dev/), including walk-throughs of _using_ the Tables.jl interface, _implementing_ it, and even some tips on _testing_
- Addition of `Tables.Row` and `Tables.Columns` convenience types for providing a ton of useful behaviors for objects returned from `Tables.rows` and `Tables.columns`, including iteration, indexing, property-access, and AbstractDict methods
- Polish of Tables.jl API requirements: in particular, `Tables.rows` must now return any `Tables.AbstractRow`-compatible iterator, and `Tables.columns` must return a `Tables.AbstractColumns`-compatible object. The interfaces for both `Tables.AbstractRow` and `Tables.AbstractColumns` are synchronized for consistency, both just requiring `Tables.getcolumn` and `Tables.columnnames` to be implemented
- The moving out of a few “table operations” to a new [TableOperations.jl](https://github.com/JuliaData/TableOperations.jl) package, where this kind of functionality can incubate and evolve separately from the core Tables.jl APIs

In general, the changes should be relatively straightforward, so the upgrade guide is:

For source implementations:

- If your table implemented `Tables.rows`, ensuring your row type implements the full [`Tables.AbstractRow`](https://juliadata.github.io/Tables.jl/dev/#Tables.AbstractRow-1) interface, instead of just `getproperty` and `propertynames`; note that `NamedTuple`s satisfy the interface by default (as they always have). For custom row types, you may consider subtyping `Tables.AbstractRow` to inherit a bunch of useful definitions (iteration, indexing, property-access, and AbstractDict methods)
- If your table implements `Tables.columns`, ensuring the returned object satisfies the full [`Tables.AbstractColumns`](https://juliadata.github.io/Tables.jl/dev/#Tables.AbstractColumns-1) interface, instead of just `getproperty` and `propertynames`. For custom columns types, you may consider subtyping `Tables.AbstractColumns` to inherit the same kind of useful default behavior as `Tables.AbstractRow`
- Depending on the nature of your table, you may consider implementing [`Tables.isrowtable`](https://juliadata.github.io/Tables.jl/dev/#Tables.isrowtable-1) to hook into some useful default definitions

For Tables.jl consumers (or sink functions):

- Just note that by default, the “row” iterator returned by `Tables.rows` doesn’t require that the row be property-accessible anymore, but only requires that `Tables.getcolumn` and `Tables.columnnames` be defined.
- You may consider using the new `Tables.Row(row)` wrapper struct that takes the new “minimal” Tables.jl row requirement, and wraps it in a struct that subtypes `Tables.AbstractRow`, meaning it makes any plain row useful by defining iteration, indexing, property-access, and AbstractDict methods. This allows any row to be treated w/ the same API you would use on a `NamedTuple`.
- Note that `Tables.eachcolumn` used to allow passing varargs through the definition, but extra args should now be passed normally via closure; so the the old definition was `Tables.eachcolumn(f, schema, row, args...)` and now it’s just `Tables.eachcolumn(f, schema, row)`
- There also used to be a definition for `Tables.eachcolumn` for columns objects (i.e. the result of calling `Tables.columns(table)`), but that’s been removed in favor of wrapping a columns object with `Tables.Columns`, which makes the object iterable, indexable, property-accessible, and support AbstractDict methods (similar to `Tables.Row`). So you can just replace `Tables.eachcolumn(columns)` with `Tables.Columns(columns)`.
- There’s a new, officially supported `Tables.namedtupleiterator(table)`, in case that’s useful to anyone; it takes any Tables.jl input table source and will iterate full `NamedTuple` rows
- `AbstractDict`s are now supported as “columns” objects (if they have a key type of `Symbol`, `String`, or `Integer` and a value type of `<:AbstractVector`), or as a “row” object; meaning a `Vector{Dict}` is a now a valid “table”

I think those are the major things to highlight; for more complete view of the package, interfaces, and APIs, check out the [new docs](https://juliadata.github.io/Tables.jl/v1.0/), feel free to [open an issue](https://github.com/JuliaData/Tables.jl/issues/new) for anything confusing or concerning, or drop by the [#data](https://julialang.slack.com/messages/data/) channel in the slack to ask questions or get some clarity. Also feel free to ping me (@quinnj) on any issues/pull requests and I’m happy to review and help people get some 1.0 goodness for their tables.

Happy tabling!

-Jacob
