FrankenTuples.jl

FrankenTuples.jl

The FrankenTuples package defines a type, FrankenTuple, which is a creature not unlike Frankenstein's monster. It is comprised of both a Tuple and a NamedTuple to facilitate situations in which some but not all elements of a tuple are named, e.g. (1, 2; a=3, b=4), and thus acts like a cross between the two.

Type and Constructors

FrankenTuple{T<:Tuple, names, NT<:Tuple}

A FrankenTuple contains a Tuple of type T and a NamedTuple with names names and types NT. It acts like a cross between the two, like a partially-named tuple.

The named portion of a FrankenTuple can be accessed using NamedTuple, and the unnamed portion can be accessed with Tuple.

Examples

julia> ft = FrankenTuple((1, 2), (a=1, b=2))
FrankenTuple((1, 2), (a = 1, b = 2))

julia> Tuple(ft)
(1, 2)

julia> NamedTuple(ft)
(a = 1, b = 2)
source
FrankenTuples.ftupleFunction.
ftuple(args...; kwargs...)

Construct a FrankenTuple from the given positional and keyword arguments.

Examples

julia> ftuple(1, 2)
FrankenTuple((1, 2), NamedTuple())

julia> ftuple(1, 2, a=3, b=4)
FrankenTuple((1, 2), (a = 3, b = 4))
source
@ftuple (x...; y...)
@ftuple (a, x=t, b, y=u)

Construct a FrankenTuple from the given tuple expression, which can contain both positional and named elements. The tuple can be "sectioned" in the same manner as a function signature, with positional elements separated from the named elements by a semicolon, or positional and named elements can be intermixed, occurring in any order.

Examples

julia> @ftuple (1, 2; a=3, b=4)
FrankenTuple((1, 2), (a = 3, b = 4))

julia> @ftuple (1, a=3, 2, b=4)
FrankenTuple((1, 2), (a = 3, b = 4))
source

API

FrankenTuples adhere as closely as makes sense to the API for Tuples and NamedTuples.

Core.TupleType.
Tuple(ft::FrankenTuple)

Access the Tuple part of a FrankenTuple, i.e. the "plain," unnamed portion.

source
Core.NamedTupleType.
NamedTuple(ft::FrankenTuple)

Access the NamedTuple part of a FrankenTuple, i.e. the named portion.

source
Base.lengthFunction.
length(ft::FrankenTuple)

Compute the number of elements in ft.

source
Base.isemptyFunction.
isempty(ft::FrankenTuple)

Determine whether the given FrankenTuple is empty, i.e. has at least 1 element.

source
Base.iterateFunction.
iterate(ft::FrankenTuple[, state])

Iterate over ft. This yields the values of the unnamed section first, then the values of the named section.

Examples

julia> ft = @ftuple (1, a=3, 2, b=4)
FrankenTuple((1, 2), (a = 3, b = 4))

julia> collect(ft)
4-element Array{Int64,1}:
 1
 2
 3
 4
source
Base.keysFunction.
keys(ft::FrankenTuple)

Get the keys of the given FrankenTuple, i.e. the set of valid indices into ft. The unnamed section of ft has 1-based integer keys and the named section is keyed by name, given as Symbols.

Examples

julia> keys(ftuple(1, 2; a=3, b=4))
(1, 2, :a, :b)
source
Base.valuesFunction.
values(ft::FrankenTuple)

Get the values of the given FrankenTuple in iteration order. The values for the unnamed section appear before that of the named section.

Examples

julia> values(ftuple(1, 2; a=3, b=4))
(1, 2, 3, 4)
source
Base.pairsFunction.
pairs(ft::FrankenTuple)

Construct a Pairs iterator that associates the keys of ft with its values.

Examples

julia> collect(pairs(ftuple(1, 2; a=3, b=4)))
4-element Array{Pair{Any,Int64},1}:
  1 => 1
  2 => 2
 :a => 3
 :b => 4
source
Base.getindexFunction.
getindex(ft::FrankenTuple, i)

Retrieve the value of ft at the given index i. When i::Integer, this gets the value at index i in iteration order. When i::Symbol, this gets the value from the named section with name i. (getproperty can also be used for the Symbol case.)

Examples

julia> ftuple(1, 2; a=3, b=4)[3]
3

julia> ftuple(1, 2; a=3, b=4)[:a]
3
source
Base.firstindexFunction.
firstindex(ft::FrankenTuple)

Retrieve the first index of ft, which is always 1.

source
Base.lastindexFunction.
lastindex(ft::FrankenTuple)

Retrieve the last index of ft, which is equivalent to its length.

source
Base.firstFunction.
first(ft::FrankenTuple)

Get the first value in ft in iteration order. ft must be non-empty.

source
Base.tailFunction.
Base.tail(ft::FrankenTuple)

Return the tail portion of ft: a new FrankenTuple with the first element of ft removed. ft must be non-empty.

Examples

julia> Base.tail(ftuple(a=4, b=5))
FrankenTuple((), (b = 5,))
source
Base.emptyFunction.
empty(ft::FrankenTuple)

Construct an empty FrankenTuple.

source
Base.eltypeFunction.
eltype(ft::FrankenTuple)

Determine the element type of ft. This is the immedate supertype of the elements in ft if they are not homogeneously typed.

Examples

julia> eltype(ftuple(1, 2; a=3, b=4))
Int64

julia> eltype(ftuple(0x0, 1))
Integer

julia> eltype(ftuple(a=2.0, b=0x1))
Real

julia> eltype(ftuple())
Union{}
source

Additional Methods

These are some additional ways to use FrankenTuples. The most interesting of these is perhaps hasmethod, which permits looking for methods that have particular keyword arguments. This is not currently possible with the generic method in Base.

Base.hasmethodFunction.
hasmethod(f::Function, ft::Type{<:FrankenTuple})

Determine whether the function f has a method with positional argument types matching those in the unnamed portion of ft and with keyword arguments named in accordance with those in the named portion of ft.

Note that the types in the named portion of ft do not factor into determining the existence of a matching method because keyword arguments to not participate in dispatch. Similarly, calling hasmethod with a FrankenTuple with an empty named portion will still return true if the positional arguments match, even if f only has methods that accept keyword arguments. This ensures agreement with the behavior of hasmethod on Tuples.

More generally, the names in the FrankenTuple must be a subset of the keyword argument names in the matching method, except when the method accepts a variable number of keyword arguments (e.g. kwargs...). In that case, the names in the method must be a subset of the FrankenTuple's names.

Examples

julia> f(x::Int; y=3, z=4) = x + y + z;

julia> hasmethod(f, FrankenTuple{Tuple{Int},(:y,)})
true

julia> hasmethod(f, FrankenTuple{Tuple{Int},(:a,)) # no keyword `a`
false

julia> g(; a, b, kwargs...) = +(a, b, kwargs...);

julia> hasmethod(g, FrankenTuple{Tuple{},(:a,:b,:c,:d)}) # g accepts arbitrarily many kwargs
true
source
FrankenTuples.ftcallFunction.
ftcall(f::Function, ft::FrankenTuple)

Call the function f using the unnamed portion of ft as its positional arguments and the named portion of ft as its keyword arguments.

Examples

julia> ftcall(mapreduce, ftuple(abs2, -, 1:4; init=0))
-30
source