Skip to content

Commit 3c1d72b

Browse files
authored
Using UnPack.jl (#112)
1 parent 8bd5822 commit 3c1d72b

File tree

3 files changed

+19
-211
lines changed

3 files changed

+19
-211
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ version = "0.12.0"
55

66
[deps]
77
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
8+
UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
89

910
[compat]
10-
OrderedCollections = "≥ 0.1.0"
11-
julia = "≥ 1.0.0"
11+
OrderedCollections = "1"
12+
UnPack = "0.1"
13+
julia = "1"
1214

1315
[extras]
1416
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"

docs/src/manual.md

Lines changed: 14 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,19 @@ Since the macro operates on a single tuple expression (as opposed to a tuple of
180180
181181
# (Un)pack macros
182182
183+
## `@unpack` and `@pack` re-exported from UnPack.jl
184+
183185
When working with parameters, or otherwise, it is often convenient to
184186
unpack (and pack, in the case of mutable datatypes) some or all of the
185187
fields of a type. This is often the case when passed into a function.
186188
187-
The preferred to do this is using the [`@unpack`](@ref) and [`@pack!`](@ref) macros
188-
which are generic and also work with non-`@with_kw` types, modules, and
189-
dictionaries (and can be customized for other types too, see next section). Continuing
190-
with the `Para` type defined above:
189+
The preferred to do this is using the `@unpack` and
190+
`@pack!` macros from the package
191+
[UnPack.jl](https://github.com/mauro3/UnPack.jl). These are generic
192+
and also work with non-`@with_kw` stucts, named-tuples, modules, and
193+
dictionaries.
194+
Here one example is given, for more see the README of
195+
UnPack. Continuing with the `Para` struct defined above:
191196
192197
```julia
193198
function fn2(var, pa::Para)
@@ -201,64 +206,14 @@ end
201206
out, pa = fn2(7, pa)
202207
```
203208
204-
Example with a dictionary:
205-
206-
```julia
207-
d = Dict{Symbol,Any}(:a=>5.0,:b=>2,:c=>"Hi!")
208-
@unpack a, c = d
209-
a == 5.0 #true
210-
c == "Hi!" #true
211-
212-
d = Dict{String,Any}()
213-
@pack! d = a, c
214-
d # Dict{String,Any}("a"=>5.0,"a"=>"Hi!")
215-
```
216-
217-
## Customization of `@unpack` and `@pack!`
218-
219-
What happens during the (un-)packing of a particular datatype is
220-
determined by the functions [`Parameters.unpack`](@ref) and
221-
[`Parameters.pack!`](@ref).
222-
223-
The `Parameters.unpack` function is invoked to unpack one entity of some
224-
`DataType` and has signature:
225-
226-
`unpack(dt::Any, ::Val{property}) -> value of property`
227-
228-
Note that `unpack` (and `pack!`) works with `Base.getproperty`. By
229-
default this means that all the fields of a type are unpacked but if
230-
`getproperty` is overloaded, then it will unpack accordingly.
231-
232-
Two definitions are included in the package to unpack a composite type/module
233-
or a dictionary with Symbol or string keys:
234-
235-
```
236-
@inline unpack{f}(x, ::Val{f}) = getproperty(x, f)
237-
@inline unpack{k}(x::Associative{Symbol}, ::Val{k}) = x[k]
238-
@inline unpack{S<:AbstractString,k}(x::Associative{S}, ::Val{k}) = x[string(k)]
239-
```
240-
241-
The `Parameters.pack!` function is invoked to pack one entity into some
242-
`DataType` and has signature:
243-
244-
`pack!(dt::Any, ::Val{field}, value) -> value`
245-
246-
Two definitions are included in the package to pack into a composite
247-
type or into a dictionary with Symbol or string keys:
248-
249-
```
250-
@inline pack!{f}(x, ::Val{f}, val) = setproperty!(x, f, val)
251-
@inline pack!{k}(x::Associative{Symbol}, ::Val{k}, val) = x[k]=val
252-
@inline pack!{S<:AbstractString,k}(x::Associative{S}, ::Val{k}, val) = x[string(k)]=val
253-
```
254-
255-
More methods can be added to `unpack` and `pack!` to allow for
256-
specialized packing of datatypes.
209+
Note that `@unpack` and `@pack!` can be customized on types,
210+
see [UnPack.jl](https://github.com/mauro3/UnPack.jl).
257211
258-
## The type-specific (un)pack macros (somewhat dangerous)
212+
## The type-specific (un)pack-all macros (somewhat dangerous)
259213
260214
The `@with_kw` macro automatically produces type-specific (un-)pack
261-
macros of form `@unpack_TypeName`, `@pack_TypeName!`, and `@pack_TypeName` which unpack/pack all fields:
215+
macros of form `@unpack_TypeName`, `@pack_TypeName!`, and
216+
`@pack_TypeName` which unpack/pack all fields:
262217
263218
```julia
264219
function fn(var, pa::Para)

src/Parameters.jl

Lines changed: 1 addition & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ c = BB.c
4343
module Parameters
4444
import Base: @__doc__
4545
import OrderedCollections: OrderedDict
46+
using UnPack: @unpack, @pack!
4647

4748
export @with_kw, @with_kw_noshow, type2dict, reconstruct, @unpack, @pack!, @pack
4849

@@ -656,154 +657,4 @@ macro with_kw_noshow(typedef)
656657
return esc(with_kw(typedef, __module__, false))
657658
end
658659

659-
660-
###########################
661-
# Packing and unpacking @unpack, @pack!
662-
##########################
663-
# Below code slightly adapted from Simon Danisch's GLVisualize via PR
664-
# https://github.com/mauro3/Parameters.jl/pull/13
665-
666-
"""
667-
This function is invoked to unpack one field/entry of some DataType
668-
`dt` and has signature:
669-
670-
`unpack(dt::Any, ::Val{property}) -> value of property`
671-
672-
The `property` is the symbol of the assigned variable.
673-
674-
Three definitions are included in the package to unpack a composite type
675-
or a dictionary with Symbol or string keys:
676-
```
677-
@inline unpack(x, ::Val{f}) where {f} = getproperty(x, f)
678-
@inline unpack(x::AbstractDict{Symbol}, ::Val{k}) where {k} = x[k]
679-
@inline unpack(x::AbstractDict{S}, ::Val{k}) where {S<:AbstractString,k} = x[string(k)]
680-
```
681-
682-
More methods can be added to allow for specialized unpacking of other datatypes.
683-
684-
See also `pack!`.
685-
"""
686-
function unpack end
687-
@inline unpack(x, ::Val{f}) where {f} = getproperty(x, f)
688-
@inline unpack(x::AbstractDict{Symbol}, ::Val{k}) where {k} = x[k]
689-
@inline unpack(x::AbstractDict{<:AbstractString}, ::Val{k}) where {k} = x[string(k)]
690-
691-
"""
692-
This function is invoked to pack one entity into some DataType and has
693-
signature:
694-
695-
`pack!(dt::Any, ::Val{property}, value) -> value`
696-
697-
Two definitions are included in the package to pack into a composite
698-
type or into a dictionary with Symbol or string keys:
699-
700-
```
701-
@inline pack!(x, ::Val{f}, val) where {f} = setproperty!(x, f, val)
702-
@inline pack!(x::AbstractDict{Symbol}, ::Val{k}, val) where {k} = x[k]=val
703-
@inline pack!(x::AbstractDict{S}, ::Val{k}, val) where {S<:AbstractString,k} = x[string(k)]=val
704-
```
705-
706-
More methods can be added to allow for specialized packing of other
707-
datatypes.
708-
709-
See also `unpack`.
710-
"""
711-
function pack! end
712-
@inline pack!(x, ::Val{f}, val) where {f} = setproperty!(x, f, val)
713-
@inline pack!(x::AbstractDict{Symbol}, ::Val{k}, val) where {k} = x[k]=val
714-
@inline pack!(x::AbstractDict{<:AbstractString}, ::Val{k}, val) where {k} = x[string(k)]=val
715-
716-
"""
717-
Unpacks fields/properties/keys from a composite type, a `Dict{Symbol}`, a `Dict{String}`,
718-
or a module into variables
719-
```julia_skip
720-
@unpack a, b, c = dict_or_typeinstance
721-
```
722-
723-
Example with dict:
724-
```julia
725-
d = Dict{Symbol,Any}(:a=>5.0,:b=>2,:c=>"Hi!")
726-
@unpack a, c = d
727-
a == 5.0 #true
728-
c == "Hi!" #true
729-
```
730-
731-
Example with type:
732-
```julia
733-
struct A; a; b; c; end
734-
d = A(4,7.0,"Hi")
735-
@unpack a, c = d
736-
a == 4 #true
737-
c == "Hi" #true
738-
```
739-
740-
Note that its functionality can be extende by adding methods to the
741-
`Parameters.unpack` function.
742-
"""
743-
macro unpack(args)
744-
args.head!=:(=) && error("Expression needs to be of form `a, b = c`")
745-
items, suitecase = args.args
746-
items = isa(items, Symbol) ? [items] : items.args
747-
suitecase_instance = gensym()
748-
kd = [:( $key = $Parameters.unpack($suitecase_instance, Val{$(Expr(:quote, key))}()) ) for key in items]
749-
kdblock = Expr(:block, kd...)
750-
expr = quote
751-
$suitecase_instance = $suitecase # handles if suitecase is not a variable but an expression
752-
$kdblock
753-
$suitecase_instance # return RHS of `=` as standard in Julia
754-
end
755-
esc(expr)
756-
end
757-
758-
759-
"""
760-
Packs variables into a mutable, composite type, a `Dict{Symbol}`, or a `Dict{String}`
761-
```julia_skip
762-
@pack! dict_or_typeinstance = a, b, c
763-
```
764-
765-
Example with dict:
766-
```julia
767-
a = 5.0
768-
c = "Hi!"
769-
d = Dict{Symbol,Any}()
770-
@pack! d = a, c
771-
d # Dict{Symbol,Any}(:a=>5.0,:c=>"Hi!")
772-
```
773-
774-
Example with type:
775-
```julia
776-
a = 99
777-
c = "HaHa"
778-
mutable struct A; a; b; c; end
779-
d = A(4,7.0,"Hi")
780-
@pack! d = a, c
781-
d.a == 99 #true
782-
d.c == "HaHa" #true
783-
```
784-
785-
Note that its functionality can be extende by adding methods to the
786-
`Parameters.pack!` function.
787-
"""
788-
macro pack!(args)
789-
esc(_pack_bang(args))
790-
end
791-
792-
function _pack_bang(args)
793-
args.head!=:(=) && error("Expression needs to be in the form of an assignment.")
794-
suitecase, items = args.args
795-
items = isa(items, Symbol) ? [items] : items.args
796-
suitecase_instance = gensym()
797-
kd = [:( $Parameters.pack!($suitecase_instance, Val{$(Expr(:quote, key))}(), $key) ) for key in items]
798-
kdblock = Expr(:block, kd...)
799-
return quote
800-
$suitecase_instance = $suitecase # handles if suitecase is not a variable but an expression
801-
$kdblock
802-
($(items...),)
803-
end
804-
end
805-
806-
# TODO: maybe add @pack_new for packing into a new instance. Could be
807-
# used with immutables also.
808-
809660
end # module

0 commit comments

Comments
 (0)