Accessors.jl icon indicating copy to clipboard operation
Accessors.jl copied to clipboard

insert not working for stucts?

Open diadora77 opened this issue 2 years ago • 6 comments

While I'm able to insert using named tuples, it doesn't seem to work for structs?

julia> using Accessors

julia> struct HelloWorld
           greeting::String
           name::String
       end

julia> x = HelloWorld("hi", "World")
HelloWorld("hi", "World")

julia> lens = @optic _.response
(@optic _.response)

julia> insert(x, lens, "goodbye")
ERROR: MethodError: no method matching insert(::HelloWorld, ::PropertyLens{:response}, ::String)
Closest candidates are:
  insert(::Any, ::ComposedFunction, ::Any) at ~/.julia/packages/Accessors/KHKiv/src/optics.jl:223
  insert(::NamedTuple, ::PropertyLens{field}, ::Any) where field at ~/.julia/packages/Accessors/KHKiv/src/optics.jl:401
  insert(::Any, ::typeof(last), ::Any) at ~/.julia/packages/Accessors/KHKiv/src/functionlenses.jl:8
  ...
Stacktrace:
 [1] top-level scope

diadora77 avatar Jan 22 '23 23:01 diadora77

What would you expect it to return? For namedtuples, the result is obvious: a namedtuple with one more field added. For structs - not so much...

aplavin avatar Jan 23 '23 00:01 aplavin

Fair enough. I was thinking that it would create a modified struct... something along the lines of:

julia> using Accessors

julia> struct HelloWorld
           greeting::String
           name::String
       end

julia> x = HelloWorld("hi", "World")
HelloWorld("hi", "World")

julia> lens = @optic _.response
(@optic _.response)

julia> insert(x, lens, "goodbye")
HelloWorld("hi", "World", "goodbye")

julia>propertynames(insert(x, lens, "goodbye"))
(:greeting, :name, :response)

As with a named tuple, it would add in the field to the struct.

diadora77 avatar Jan 23 '23 00:01 diadora77

Creating a new struct efficiently is impossible from within a function, I think. And anyway, what's the usecase for this? The new struct would bear no relation to the original one, no methods defined for original HelloWorld would work for the output.

Remember, Accessors is no magic: it's effectively a convenient interface to already available functionality.

aplavin avatar Jan 23 '23 00:01 aplavin

Right. I have a scenario where there are nested structs. Buried within the nested structs are some optional extension fields that may or not exist at time of creation. Long story short, structs are created based on known fields however additional extension fields need to be added in at a later time. I was hoping I could use Accessors to insert the optional fields into the existing struct instances. As you said, Acccessors is convenient and a potential three-liner is much more appealing than iterating/unpacking existing struct for modification.

diadora77 avatar Jan 23 '23 01:01 diadora77

Yeah, thats just not possible in julia, you can't modify a struct. That's one reason julia can be fast vs e.g. Python, structs are basically C structs, not dictionaries.

But if you want the flexibility of a NamedTuple with a type you can dispatch on, just make a struct that wraps a NamedTuple. Then you can do what you want.

rafaqz avatar Jan 23 '23 08:01 rafaqz

Well, the point of Accessors is to update/modify immutable types? Right? It's advertised as such for NamedTupes and "arbitrary structs and nested updates" per documentation. There are examples where immutable structs are modified. In interpreting the responses, is it fair to say that Accessors can update/modify structs but not "insert" or add fields. If so, perhaps make a clarifying remark(s) in the documentation?

diadora77 avatar Jan 29 '23 21:01 diadora77