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

Remove mutation support #34

Merged
merged 6 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ os:
- linux
- osx
julia:
- 0.6
- 0.7
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add 1.0 too! #35 🎉

- 1.0
- nightly
notifications:
email: false
Expand All @@ -25,13 +26,10 @@ git:
#before_script: # homebrew for mac
# - if [ $TRAVIS_OS_NAME = osx ]; then brew install gcc; fi

# uncomment the following lines to override the default test script
script:
- julia -e 'Pkg.clone(pwd()); Pkg.build("Setfield"); VERSION < v"0.7-" && Pkg.add("StaticArrays"); Pkg.test("Setfield"; coverage=true)'
after_success:
# push coverage results to Coveralls
- julia -e 'cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
- julia -e 'using Pkg; cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
# push coverage results to Codecov
- julia -e 'cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'
- julia -e 'Pkg.add("Documenter")'
- julia -e 'cd(Pkg.dir("Setfield")); include(joinpath("docs", "make.jl"))'
- julia -e 'using Pkg; cd(Pkg.dir("Setfield")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'
- julia -e 'using Pkg; Pkg.add("Documenter")'
- julia -e 'using Pkg; cd(Pkg.dir("Setfield")); include(joinpath("docs", "make.jl"))'
4 changes: 2 additions & 2 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
julia 0.6
MacroTools
julia 0.7-
MacroTools 0.4.4
17 changes: 2 additions & 15 deletions src/Setfield.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
__precompile__(true)
module Setfield

if isdefined(Base, :getproperty)
using Base: getproperty
else
const getproperty = getfield
# the following breaks type stability:
# @inline getproperty(obj, name) = getfield(obj, name)
end
if isdefined(Base, :setproperty!)
using Base: setproperty!
else
const setproperty! = setfield!
# @inline setproperty!(obj, name, val) = setfield!(obj, name, val)
end
using MacroTools
using MacroTools: isstructdef, splitstructdef

include("lens.jl")
include("sugar.jl")
include("macrotools.jl")
include("settable.jl")
end
40 changes: 11 additions & 29 deletions src/lens.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ export Lens, set, get, modify
export @lens
export set, get, modify

import Base: get, setindex

abstract type MutationPolicy end
struct EncourageMutation <: MutationPolicy end
struct ForbidMutation <: MutationPolicy end
import Base: get
using Base: setindex, getproperty

"""
Lens
Expand Down Expand Up @@ -74,17 +71,15 @@ Replace a deeply nested part of `obj` by `val`. See also [`Lens`](@ref).
"""
function set end

set(l::Lens, obj, val) = set(l,obj,val,ForbidMutation())
modify(f,l::Lens, obj) = modify(f, l,obj,ForbidMutation())
@inline function modify(f, l::Lens, obj, m::MutationPolicy)
@inline function modify(f, l::Lens, obj)
old_val = get(l, obj)
new_val = f(old_val)
set(l, obj, new_val, m)
set(l, obj, new_val)
end

struct IdentityLens <: Lens end
get(::IdentityLens, obj) = obj
set(::IdentityLens, obj, val,::MutationPolicy) = val
set(::IdentityLens, obj, val) = val

struct PropertyLens{fieldname} <: Lens end

Expand All @@ -99,14 +94,8 @@ function assert_hasfield(T, field)
end
end

@generated function set(l::PropertyLens{field}, obj, val, m::MutationPolicy) where {field}
T = obj
M = m
if T.mutable && (M == EncourageMutation)
:(setproperty!(obj, field, val); obj)
else
:(setproperty(obj, Val{field}(), val))
end
@generated function set(l::PropertyLens{field}, obj, val) where {field}
:(setproperty(obj, Val{field}(), val))
end

@generated constructor_of(::Type{T}) where T =
Expand Down Expand Up @@ -146,22 +135,15 @@ function get(l::ComposedLens, obj)
get(l.lens1, inner_obj)
end

function set(l::ComposedLens, obj, val, m::MutationPolicy)
function set(l::ComposedLens, obj, val)
inner_obj = get(l.lens2, obj)
inner_val = set(l.lens1, inner_obj, val, m)
set(l.lens2, obj, inner_val, m)
inner_val = set(l.lens1, inner_obj, val)
set(l.lens2, obj, inner_val)
end

struct IndexLens{I <: Tuple} <: Lens
indices::I
end

get(l::IndexLens, obj) = getindex(obj, l.indices...)
set(l::IndexLens, obj, val, ::ForbidMutation) = Base.setindex(obj, val, l.indices...)
function set(l::IndexLens, obj, val, ::EncourageMutation)
if applicable(setindex!, obj, val, l.indices)
setindex!(obj, val, l.indices...)
else
set(l, obj, val, ForbidMutation())
end
end
set(l::IndexLens, obj, val) = setindex(obj, val, l.indices...)
69 changes: 0 additions & 69 deletions src/macrotools.jl

This file was deleted.

11 changes: 5 additions & 6 deletions src/settable.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
export @settable
using MacroTools: prewalk, splitdef, combinedef
using MacroTools: prewalk
using MacroTools: splitdef, combinedef
using MacroTools: splitstructdef, isstructdef, combinestructdef

macro settable(ex)
if VERSION < v"0.7-"
__module__ = current_module()
end
esc(settable(__module__, ex))
end

Expand Down Expand Up @@ -87,15 +86,15 @@ function posonly_constructor(dtype::Dict)::Expr
end

function add_posonly_constructor(ex::Expr)::Expr
dtype = splittypedef(ex)
dtype = splitstructdef(ex)
if isempty(dtype[:constructors])
ex
elseif has_posonly_constructor(dtype)
ex
else
push!(dtype[:constructors], posonly_constructor(dtype))
@assert has_posonly_constructor(dtype)
combinetypedef(dtype)
combinestructdef(dtype)
end
end

Expand Down
48 changes: 4 additions & 44 deletions src/sugar.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export @set, @set!, @lens
export @set, @lens
using MacroTools

"""
Expand Down Expand Up @@ -27,48 +27,11 @@ T(T(2, 2), 2)
julia> @set t.a.b = 3
T(T(2, 3), 2)
```
See also [`@set!`](@ref).
"""
macro set(ex)
atset_impl(ex)
end

"""
@set! assignment

Update deeply nested parts of an object. In contrast to `@set`, `@set!`
overwrites the variable binding and mutates the original object
if possible.
```jldoctest
julia> using Setfield

julia> struct T;a;b end

julia> t = T(1,2)
T(1, 2)

julia> @set! t.a = 5
T(5, 2)

julia> t
T(5, 2)

julia> @set t.a = 10
T(10, 2)

julia> t
T(5, 2)
```
### Warning
Since `@set!` rebinds the variable, it will cause type instabilites
for updates that change the type.

See also [`@set`](@ref).
"""
macro set!(ex)
atset_impl(ex, :(EncourageMutation()), true)
end

function parse_obj_lenses(ex)
if @capture(ex, front_[indices__])
obj, frontlens = parse_obj_lenses(front)
Expand Down Expand Up @@ -103,7 +66,7 @@ struct _UpdateOp{OP,V}
end
(u::_UpdateOp)(x) = u.op(x, u.val)

function atset_impl(ex::Expr, mut=:(ForbidMutation()), rebind=false)
function atset_impl(ex::Expr)
@assert ex.head isa Symbol
@assert length(ex.args) == 2
ref, val = ex.args
Expand All @@ -112,18 +75,15 @@ function atset_impl(ex::Expr, mut=:(ForbidMutation()), rebind=false)
ret = if ex.head == :(=)
quote
lens = $lens
set(lens, $obj, $val, $mut)
set(lens, $obj, $val)
end
else
op = UPDATE_OPERATOR_TABLE[ex.head]
f = :(_UpdateOp($op,$val))
quote
modify($f, $lens, $obj, $mut)
modify($f, $lens, $obj)
end
end
if rebind
ret = :($obj = $ret)
end
ret
end

Expand Down
5 changes: 0 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ using Setfield
include("test_core.jl")
end

@testset "macrotools" begin
include("test_macrotools.jl")
end
@testset "settable" begin
include("test_settable.jl")
end
Expand All @@ -35,10 +32,8 @@ end
include("test_kwonly.jl")
end

@static if VERSION < v"0.7-"
@testset "QuickTypes.jl" begin
include("test_quicktypes.jl")
end
end

end # module
Loading