Actually, a slightly better form might be:
@generated function modify_field{g}(x, ::Type{Val{g}}, v)
F = fieldnames(x)
D = Any[:(x.$f) for f in F]
D[F .== g] = :v
Expr(:call, :call, x, D...)
end
This avoids the need to call symbol (I don't know if this could be a
problem, but it does seem safer).
On Tuesday, 2 June 2015 10:00:39 UTC+1, Simon Byrne wrote:
>
> You could use the eltype function, but having thought more about it, I
> think it might be easier (and more general) if you operate on the objects
> instead of the container. Something like:
>
> @generated function modify_field{g}(x, ::Type{Val{g}}, v)
> F = fieldnames(x)
> D = Any[:(x.$f) for f in F]
> D[F .== g] = :v
> Expr(:call, symbol(x), D...)
> end
>
> macro modify_field!(ex)
> ex.head == :(=) && ex.args[1].head == :(.) || error("Invalid usage of
> @modify_field! macro")
> lhs, v = ex.args
> x, g = lhs.args
> :($(esc(x)) = modify_field($(esc(x)), Val{$g}, $v))
> end
>
> Note that modify_field doesn't actually change anything (it creates a new
> instance), the re-assignment is done by the macro, e.g.:
>
> immutable Immut
> intfld::Int
> isadded::Bool
> end
>
> Y = [Immut(i,false) for i = 1:10]
> for i = 1:5
> @modify_field! Y[i].isadded = true
> end
> Y
>
> This also allows you to use it without an array
>
> y = Immut(1,false)
> @modify_field! y.isadded = true
> y
>
> That said, I haven't done any profiling to compare speed.
>
> -Simon
>
>
> On Tuesday, 2 June 2015 03:24:51 UTC+1, [email protected] wrote:
>>
>> Simon,
>>
>> Sorry to follow up so quickly on my own post, but I'm not able to figure
>> out how to use generated functions for this purpose. Consider:
>>
>> modifyField!(a,k,Val{:isadded}, true)
>>
>> The generated-function routine modifyField! needs to know the base type
>> of a. In other words, there exists some base type, say Immut, such that a
>> is an array of Immut's or a dict of Immut's or some other container, and
>> :isadded is one of the fields of Immut. (The generator function
>> modifyField! needs to know about Immut in order to enumerate all of its
>> other fields).
>>
>> I don't see how to determine this base type within the generator. Say,
>> for example, that the type of a is Array{Immut,1}. I was hoping that one
>> of the following introspective calls would work:
>>
>> methodswith(typeof(a), setindex!, false)
>> methodswith(typeof(a), setindex!, true)
>>
>> but neither worked -- the first did not return any methods, whereas the
>> second returned a huge list of methods without any clear winner. Another
>> possibility might be:
>>
>> code_typed(getindex, (typeof(a), typeof(k))
>>
>> but I didn't know how to analyze this output for the general case; it
>> seems like determining the return value of getindex is as hard as the
>> halting problem!
>>
>> Thanks,
>> Steve
>>
>>
>> On Monday, June 1, 2015 at 5:57:19 PM UTC-4, Simon Byrne wrote:
>>>
>>> That's some impressive metaprogramming. In v0.4, you should be able to
>>> do this without the "maker" functions, using generated functions
>>>
>>> http://julia.readthedocs.org/en/latest/manual/metaprogramming/#generated-functions
>>>
>>> As far as an interface goes, I would suggest a macro, e.g. so that the
>>> user could write something like
>>>
>>> @modify! a[i].field = new
>>>
>>>
>>> On Monday, 1 June 2015 03:09:29 UTC+1, [email protected] wrote:
>>>>
>>>> Following up on an earlier discussion that I started in this newsgroup,
>>>> I have written a small package that provides a routine to modify a field
>>>> of
>>>> an immutable object in the case that the object is inside a container.
>>>> Please refer to:
>>>>
>>>> https://github.com/StephenVavasis/Modifyfield.jl
>>>> <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2FStephenVavasis%2FModifyfield.jl&sa=D&sntz=1&usg=AFQjCNEMQeocqbzVy4CBDgPjAQNZhmq8Fg>
>>>>
>>>> Feedback is welcome.
>>>>
>>>>
>>>>