# With struct do

**URL:** <https://discourse.julialang.org/t/with-struct-do/41341>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [June 13, 2020, 9:22pm UTC](https://discourse.julialang.org/t/with-struct-do/41341 "2020-06-13T21:22:19Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![janrpeters](https://avatars.discourse-cdn.com/v4/letter/j/d26b3c/32.png) [@janrpeters](https://discourse.julialang.org/u/janrpeters)\
**Post date:** [June 13, 2020, 9:22pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/1 "2020-06-13T21:22:19Z")

</div>

A long time ago, I learned Turbo Pascal and there was a contract that allowed:

```julia
with x do 
     field3 = field1 + field2    
end

```

instead of

`x.field3 = x.field1 + x.field2`

where

```julia
mutable struct compositetype
     field1
     field2
     field3
end

x = compositetype(1,2);

```

Is that possible in Julia?

---

<div class="post-metadata">

**Author:** ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)\
**Post date:** [June 13, 2020, 9:44pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/2 "2020-06-13T21:44:14Z")

</div>

You could write a macro to do something a bit like this, although it hits a bunch of problems with figuring out which symbols in the expression could be fields in the struct: a macro can’t know that information, so you’d need purely syntactic rules to determine whether something’s a field. In particular, how do you handle the case in which the struct contains a function in it?

```julia
with x do
    field3 = field4(field1, exp(field2))
end

```

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [June 13, 2020, 9:46pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/3 "2020-06-13T21:46:22Z")

</div>

There is not currently anything like this, I think. `@unpack` from Unpack.jl gives you something similar.

DataFramesMeta and other `Meta` packages will also let you do this in some way, if you need help figuring out how to write a macro for this.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [June 13, 2020, 10:17pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/4 "2020-06-13T22:17:07Z")

</div>

I think [PatameterisedModule.jl](https://github.com/thautwarm/ParameterisedModule.jl) by @thautwarm may do what you want. It may be a bit too fancy for your uses though. I certainly don’t really ‘get’ it as I never used Ocaml.

* * *

Edit: Nevermind, it appears to only support immutable types if I understand correctly.

---

<div class="post-metadata">

**Author:** ![Mattriks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mattriks/32/351_2.png) [@Mattriks](https://discourse.julialang.org/u/Mattriks)\
**Post date:** [June 13, 2020, 10:27pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/5 "2020-06-13T22:27:52Z")

</div>

Julia also has [functors](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects-1).

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [June 13, 2020, 10:31pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/6 "2020-06-13T22:31:41Z")

</div>

Could you expand on how that would help the OP do what they ask?

---

<div class="post-metadata">

**Author:** ![Mattriks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mattriks/32/351_2.png) [@Mattriks](https://discourse.julialang.org/u/Mattriks)\
**Post date:** [June 13, 2020, 10:46pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/7 "2020-06-13T22:46:48Z")

</div>

I’m giving the user more options, so they can think about how they want to write their program. The functor looks pretty close to the `x = compositetype(1,2)` line in the OP (and so does an outer constructor!).

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [June 14, 2020, 5:20am UTC](https://discourse.julialang.org/t/with-struct-do/41341/8 "2020-06-14T05:20:13Z")

</div>

I came up with something here: [Unpack named tuples (does anyone know how to do it?) - #13 by Mason](https://discourse.julialang.org/t/unpack-named-tuples-does-anyone-know-how-to-do-it/32456/13) but I don’t think there’s any good way to turn a `setfield!` statement like the one you show: `field3 = field1 + field2 ` into `x.field3 = x.field1 + x.field2` so I posted it in the other thread rather than this one.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 14, 2020, 6:41am UTC](https://discourse.julialang.org/t/with-struct-do/41341/9 "2020-06-14T06:41:39Z")

</div>

> [@janrpeters](#):
>
> Is that possible in Julia?

Not directly. As others have suggested, various approximations exist, but fundamentally this kind of a construct does not fit well into the way Julia works.

In a nutshell, the meaning of `field3` etc in a `with` block would need to depend on the type of `x`, which may or may not be known at compile time. Consider

```julia
function f!(x)
    with x do # ****NOTE: hypothetical syntax****
        field3 = field1 + field2    
    end
    x
end

mutable struct Foo
    field1
    field2
end

mutable struct Bar
    field1
    field2
    field3
end

f!(Foo(1, 2))
f!(Bar(1, 2, 4))

```

What should `f!(Foo(1, 2))` do? Should it treat `field3` as a local variable, which is then optimized out as unused? This could lead to very insidious bugs.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [June 14, 2020, 12:53pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/10 "2020-06-14T12:53:29Z")

</div>

OP, another solution is [Lazy.jl](https://github.com/MikeInnes/Lazy.jl)’s `@as` functionality. If the variable you are working with has a long name, you can shorten it in a block using `@as`.

```julia
julia> my_very_long_nt = (a = 1, b = 2)
(a = 1, b = 2)

julia> @as t my_very_long_nt begin
       t.a + t.b
       end
3

```

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [June 14, 2020, 4:31pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/11 "2020-06-14T16:31:47Z")

</div>

If the threaded arguments from `@as` are not needed, why not a `let` block:

```julia
let t = my_very_long_nt
    t.a + t.b
end

```

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [June 14, 2020, 6:04pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/12 "2020-06-14T18:04:14Z")

</div>

If you’re willing to explicitly mark which symbols should be treated as fields, then this is easier to implement. Here’s a macro which will replace all expressions of the form `&a` with `container.a`:

```julia
julia> using MacroTools: postwalk

julia> macro with(container, expr)
         esc(postwalk(expr) do ex
           if @capture(ex, &field_)
             :(($container).$field)
           else
             ex
           end
         end)
       end
@with (macro with 1 method)

```

Usage:

```julia
julia> mutable struct Bar
           field1
           field2
           field3
       end

julia> b = Bar(1, 2, 0)
Bar(1, 2, 0)

julia> @with b begin
         &field3 = &field1 + &field2
       end
3

julia> b
Bar(1, 2, 3)

```

This implementation doesn’t have any problem with local variables which happen to match the names of fields, since the user is responsible (by adding `&`) for explicitly marking which symbols should be treated as fields:

```julia
julia> field1 = π
π = 3.1415926535897...

julia> @with b begin
         # The left-hand side is unambiguously `b.field1` 
         # and the right-hand side is unambiguously
         # the local variable `field1`.
         &field1 = field1
       end
π = 3.1415926535897...

julia> b
Bar(π, 2, 3)

```

---

<div class="post-metadata">

**Author:** ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)\
**Post date:** [June 15, 2020, 2:14pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/13 "2020-06-15T14:14:11Z")

</div>

They’re not the same “functor”.

`functor` in C++ is just a callable, that’s quite a simple thing and not suggestive enough to abstraction tasks in programming.

The category theory has a concept called `functor`, and specifically, something called `endofunctor` will always take the place of a general “functor”, in programming fields, because usually only “endofunctor” is useful for programming.

What I meant by `functor` is close to the second meaning mentioned above:  
When we have a module `A`(like a category), and a functor `F` that maps it to another module `F(A)`, where some types (like `A.t`) in module `A` will be mechanically mapped to `F(A.t)`, as well as values and functions.

A function `f` defined in the module `A`, transforms a value typed `A.t1` to a value typed `A.t2`, it will be mapped correspondingly into module `F(A)`, as a function `F(f)`.

`F(f)` transforms a value typed `F(A.t1)` to a value typed `F(A.t2)`.

| | original | mapped |
| --- | --- | --- |
| module | A | F(A) |
| type | t | F(t) |
| a function’s “effect” | from t1 to t2 | from F(t1) to F(t2) |

See [Catlab.jl](https://github.com/epatters/Catlab.jl), they’re professional and they should have shown use cases of this `functor`.

---

<div class="post-metadata">

**Author:** ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)\
**Post date:** [June 15, 2020, 2:22pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/14 "2020-06-15T14:22:04Z")

</div>

> [@Tamas\_Papp](#):
>
> > [@janrpeters](#):
> >
> > Is that possible in Julia?
> 
> Not directly. As others have suggested, various approximations exist, but fundamentally this kind of a construct does not fit well into the way Julia works.
> 
> In a nutshell, the meaning of `field3` etc in a `with` block would need to depend on the type of `x` , which may or may not be known at compile time. Consider
> 
> ```julia
> function f!(x)
> with x do # ****NOTE: hypothetical syntax****
> field3 = field1 + field2    
> end
> x
> end
> 
> mutable struct Foo
> field1
> field2
> end
> 
> mutable struct Bar
> field1
> field2
> field3
> end
> 
> f!(Foo(1, 2))
> f!(Bar(1, 2, 4))
> 
> ```

This one is already available… with GeneralizedGenerated.jl, but I hope users do not write code like this…

> [@Tamas\_Papp](#):
>
> What should `f!(Foo(1, 2))` do? Should it treat `field3` as a local variable, which is then optimized out as unused? This could lead to very insidious bugs.

Locally and implicitly binding variables from data structures is not a new thing, in some other languages they widely use this.

`with!` treats the fields as-is(visiting these variables means accessing fields), `with` unpacks and binds the fields to local variables. This makes sense to me.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [June 15, 2020, 2:27pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/15 "2020-06-15T14:27:02Z")

</div>

Is there a good tutorial on how to do this? In particular, is there a way to evaluate `field1` instead of using its variable name as a literal? i.e. `x = :field1` and `&x` still get `field1`?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [June 15, 2020, 2:33pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/16 "2020-06-15T14:33:43Z")

</div>

No, `&x` unambiguously means `container.x` not `container.(whatever the value of the variable `x` currently is)`. This is a purely syntactic transformation, so the values of variables cannot affect the code produced by the macro.

If you want to set a struct field using a name contained in a variable, then you need `setproperty!` instead.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 15, 2020, 2:34pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/17 "2020-06-15T14:34:28Z")

</div>

> [@thautwarm](#):
>
> Locally and implicitly binding variables from data structures is not a new thing, in some other languages they widely use this.

I am aware of this (eg R does this — it is even called `with`), I just don’t think it is a good thing as it can lead to very messy code.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [June 15, 2020, 3:43pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/18 "2020-06-15T15:43:43Z")

</div>

Thanks! One other question, sorry to bother you. Do you know how to `@capture` a symbol literal? Like, not any particular symbol literal, but do something if an expression is just a symbol literal.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [June 15, 2020, 3:52pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/19 "2020-06-15T15:52:31Z")

</div>

The easiest way is just:

```julia
if x isa Symbol
  ...
end

```

If you prefer to work in `@capture` syntax, you can use the `_Symbol` suffix:

```julia
julia> @capture(:hello, x_Symbol)
true

julia> x
:hello

```

see: [https://mikeinnes.github.io/MacroTools.jl/stable/pattern-matching/#Matching-on-expression-type-1](https://mikeinnes.github.io/MacroTools.jl/stable/pattern-matching/#Matching-on-expression-type-1)

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [June 15, 2020, 3:59pm UTC](https://discourse.julialang.org/t/with-struct-do/41341/20 "2020-06-15T15:59:02Z")

</div>

Hmmm still doesn’t work. (I’m playing around with implementing some DataFramesMeta features to try and learn about it).

If the mods want to break this into a new thread I would appreciate it.

```julia
using DataFrames
using MacroTools
using MacroTools: postwalk

macro with(container, expr)
  esc(postwalk(expr) do ex
    if @capture(ex, &field_)
      quote 
        $field isa Union{<:Integer, <:AbstractString, Symbol} ? 
          getindex($container, !, $field) :
          Tables.columntable(getindex($container, !, $field))
      end
      elseif @capture(ex, x_Symbol)   
        :(getindex($container, !, $x))
      else
        ex
      end
  end)
end

df = DataFrame(rand(2,2))
@with df begin
    :x1
end

```
