# Is there a \`with\` operator or usage pattern?

**URL:** https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693
**Category:** New to Julia
**Tags:** question
**Created:** [January 1, 2021, 1:05pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693 "2021-01-01T13:05:06Z")
**Posts on this page:** 12
**Page:** 2

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [January 1, 2021, 11:58pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/21 "2021-01-01T23:58:15Z")

</div>

> [@cce](#):
>
> I mean, Julia already knows what fields are in my tuple, why should I have to tell it again? Thanks!

I think your problem comes from the fact this little claim _“Julia already knows what fields are in my tuple”_ is not well defined. Inside a macro, Julia, in fact, **does not** know what fields are in your tuple. The macro are executed before the function is compiled, and it has no information about the values (and therefore the types) of the symbols/expressions passed to them, they only know about the symbols themselves.

This is, a macro takes as arguments the text/“source code” you are passing to it, without any values inside the bindings or anything. It has no way to know the binding `var` you passed has a value of type `T` that has fields `a`, `b`, and `c` which it could expand to `a, b, c = var.a, var.b, var.c`. This is the reason `@unpack` works the way it works, it needs the user to pass to it the names of the variables, so it knows what to extract from the symbol `var` that may have any value (or even not be defined) in runtime.

A macro can expand to a call of `fieldnames` (which return a list of the `struct` fields) to construct a `Dict` (mapping the name of a field to the field in the correct struct) in _runtime_ and the macro can also expand the reference to bindings in your expression to queries in such `Dict` (which would also happen in runtime). The result would be a code many times slower than the one done by hand.

---

<div class="post-metadata">

### Author: ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)
#### Post date: [January 2, 2021, 4:03am UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/22 "2021-01-02T04:03:55Z")

</div>

First, I fully agree with everyone here that this kind of thing tends to be a footgun and using UnPack leads to far more readable code.

That said, worth pointing out that while you can’t do this with macros since as said above they only operate on expessions, you can do it quite cleanly with generated functions, which also have access to the _type_ of your object, as well as lowered code to get the scoping right. Here’s a MWE:

```julia
using MacroTools: postwalk
@generated function with(func, obj::T) where {T}
    method = Base._methods_by_ftype(Tuple{func}, -1, typemax(UInt64))[1][3]
    code = Base.uncompressed_ast(method).code
    ir_to_expr(i) = postwalk(x -> x isa Core.SSAValue ? ir_to_expr(x.id) : x, code[i])
    postwalk(ir_to_expr(length(code))) do x
        x isa GlobalRef && hasfield(T,x.name) ? :(obj.$(x.name)) : x
    end
end

subtotal = (price=12.99, shipping=3.99)
handling = 0.99

with(subtotal) do
    price + shipping + handling
end # 17.97

```

And if you check out the generated code, its optimal / inferred:

```julia
julia> @code_warntype with(subtotal) do
           price + shipping
       end

Body::Float64
1 ─ %1 = Base.getproperty(obj, :price)::Float64
│ %2 = Base.getproperty(obj, :shipping)::Float64
│ %3 = (%1 + %2)::Float64
└── return %3

```

This works in a local scope too as long as you don’t use other local variables, although thats just a limitation of the way I wrote it, you could fix that by doing a better job of modifying the IR code than the simple thing I did above. Someone with more expertise can probably do something even cleaner, maybe with Cassette or IRTools or something, but it was fun to work out this proof of concept.

---

<div class="post-metadata">

### Author: ![cce](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cce/32/460_2.png) [@cce](https://discourse.julialang.org/u/cce)
#### Post date: [January 2, 2021, 1:26pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/23 "2021-01-02T13:26:13Z")

</div>

@MA_Laforge If you update your example to be a complete MWE that defines the structure and uses `let`, I’d be delighted to switch the “solution” for new Julia developers who are looking for the simple, canonical replacement pattern.

@marius311 – that’s amazing. I’d love a performant implementation that works at multiple levels where prefixes aren’t needed. Given how many attempts at `@with` there are, it’d be great if one were type stable.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [January 2, 2021, 2:39pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/24 "2021-01-02T14:39:23Z")

</div>

One easier possibility to implement efficiently would be to write `@with` macro where you mark the expressions that are fields, e.g.:

```julia
@with subtotal begin
    _.price + _.shipping + _.handling
end

```

---

<div class="post-metadata">

### Author: ![cce](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cce/32/460_2.png) [@cce](https://discourse.julialang.org/u/cce)
#### Post date: [January 2, 2021, 2:53pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/25 "2021-01-02T14:53:58Z")

</div>

@stevengj So, I’m trying to separate two concerns: (a) where the variables are coming from, with (b) how they are used. Sometimes this is helpful (and sometimes it’s not). In @marius311’s example, the `handling` variable comes from the global context and is not treated any differently as `price` and `shipping`.

```julia
subtotal = (price=12.99, shipping=3.99)
handling = 0.99

with(subtotal) do
    price + shipping + handling
end # 17.97

```

---

<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: [January 2, 2021, 4:24pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/26 "2021-01-02T16:24:08Z")

</div>

@stevengj that’s exactly what I did above: [Is there a `with` operator or usage pattern? - #13 by rdeits](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/13)

---

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [January 3, 2021, 3:34am UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/27 "2021-01-03T03:34:53Z")

</div>

> [@cce](#):
>
> @MA_Laforge If you update your example to be a complete MWE that defines the structure and uses `let` , I’d be delighted to switch the “solution” for new Julia developers who are looking for the simple, canonical replacement pattern.

Not certain I fully understand what you are looking for in your book, esp. given the complexity of your example here:

> [@cce](#):
>
> ```julia-auto
> for o in orders
> let region = o.region, last_name = o.last_name
> for l in o.lines
> let amount = l.amount, product = l.product, size = l.size
> println(last_name, " ", product, " ",   
> (amount * discount) + (region*size))
> end
> end
> end
> end 
> 
> ```

### A simple solution

but I’ll try my best to provide an example of what I think you are seeking in a “simple, canonical replacement pattern”:

```julia-auto
mutable struct Customer
	name::String
	city::String
	country::String
	additionalInfo::Array{String}
end
Customer() = Customer("", "", "", [])

function generateDummyCustomer()
	newCustomer = Customer()
	let c = newCustomer
		c.name = "Alfred Customer"
		c.city = "Boston"
		c.country = "United States"
	end
	let i = newCustomer.additionalInfo
		push!(i, "Good customer")
		push!(i, "Provides useful feedback")
	end
	return newCustomer
end

```

### Other suggestions for temporary variable

Since I don’t often like using “`i`” for anything but iterators (or `Complex(0,1)`), other alternatives are:

- `let info = newCustomer.additionalInfo` (Use a succinct/clear alias)
- `let x = newCustomer.additionalInfo` (`x` is usually a good “go-to”)
- `let o = newCustomer.additionalInfo` (`o` is often an acceptable variable for “objects”)

In theory, I also like @stevengj’s idea of using “`_`” - but I found Julia complains when an “all-underscore identifier” is used on the RHS:

```julia
julia> _ = 3; a=4
4

julia> b = _ + a
ERROR: syntax: all-underscore identifier used as rvalue
Stacktrace:
 [1] top-level scope at REPL[11]:1

```

---

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [January 3, 2021, 3:42am UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/28 "2021-01-03T03:42:15Z")

</div>

Note that I changed the example a bit because I’m guessing you don’t want to put in a copy Microsoft code in your book.

I also don’t like that (I can only guess) the example they used probably needs to be manipulating global variables somehow.

- In VB `Private Sub AddCustomer()` can’t return a value (last I checked).
- That means the `Customer()` constructor would have to store itself somewhere accessible through a form of global variable to be useful.

Then again: I don’t think I’ve programmed in VB in over 10 years (Mostly Julia’s fault).

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [January 3, 2021, 2:32pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/29 "2021-01-03T14:32:47Z")

</div>

> [@rdeits](#):
>
> Note that this doesn’t work at all within a function:

I can fix this by throwing in a `Base.invokelatest` invocation into the macro.

```julia
julia> function genfunc(nt, body)
           local props = propertynames(nt)
           f = :( (; $(props...) )-> $body )
           g = Meta.eval(f)
       end
genfunc (generic function with 1 method)

julia> macro with(nt,body)
           local b = QuoteNode(body)
           quote
               let f = genfunc($(esc(nt)), $b)
                   Base.invokelatest(f; $(esc(nt))...)
               end
           end
       end
@with (macro with 1 method)

julia> function f(subtotal)
           @with subtotal begin
                price + shipping
           end
       end
f (generic function with 1 method)

julia> subtotal = (price=12.99, shipping=3.99)
(price = 12.99, shipping = 3.99)

julia> f(subtotal)
16.98

```

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [January 3, 2021, 2:46pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/30 "2021-01-03T14:46:16Z")

</div>

One last thought:

```julia
julia> function with(f; kwargs...)
           d = Dict(kwargs...)
           f(d)
       end
with (generic function with 1 method)

julia> with(;subtotal...) do d
           d[:price] + d[:shipping]
       end
16.98

```

---

<div class="post-metadata">

### Author: ![cce](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cce/32/460_2.png) [@cce](https://discourse.julialang.org/u/cce)
#### Post date: [January 3, 2021, 4:01pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/31 "2021-01-03T16:01:23Z")

</div>

The following is a restatement of `with` from Visual Basic, and an comparable pattern in Julia that doesn’t rely upon macros.

> [@MA\_Laforge](#):
>
> ### VB `with` pattern
> 
> ```julia
> Private Sub AddCustomer()
> Dim theCustomer As New Customer
> 
> With theCustomer
> .Name = "Coho Vineyard"
> .URL = "http://www.cohovineyard.com/"
> .City = "Redmond"
> End With
> 
> With theCustomer.Comments
> .Add("First comment.")
> .Add("Second comment.")
> End With
> End Sub
> 
> ```
> 
> ### Comparable (simple) Julia Pattern
> 
> Since, in Julia, you don’t allocate new memory with variables (you basically create a new reference), you can do something fairly similar without any special macros or anything:

> [@MA\_Laforge](#):
>
> ```julia
> function generateDummyCustomer()
> newCustomer = Customer()
> let c = newCustomer
> c.name = "Alfred Customer"
> c.city = "Boston"
> c.country = "United States"
> end
> let i = newCustomer.additionalInfo
> push!(i, "Good customer")
> push!(i, "Provides useful feedback")
> end
> return newCustomer
> end
> 
> ```

Thank you @MA_Laforge

---

<div class="post-metadata">

### Author: ![joshday](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joshday/32/368_2.png) [@joshday](https://discourse.julialang.org/u/joshday)
#### Post date: [December 13, 2021, 5:08pm UTC](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693/32 "2021-12-13T17:08:21Z")

</div>

> [@Tamas\_Papp](#):
>
> Note that this solution uses `eval` , which breaks a lot of things that would otherwise work, eg type inference:

Quick update! I’ve changed `PropertyUtils.@with` to no longer use `eval`.

Voila, no more `Any` with your example:

```julia
julia> @code_warntype f((a = 1, b = 2))
...
5 ┄ %13 = @_5::Int64
│ %14 = (%7 + %13)::Int64
└── return %14

```

[Previous page](https://discourse.julialang.org/t/is-there-a-with-operator-or-usage-pattern/52693.md?page=1)
