Obligatory life update: the most time-crunchy part of my move is over, and my life and health are stabilizing. I still need to spend a bunch of time on administrative issues, but I should have some room in my life for blogging too. _Some._

A good sign that I'm getting my brain back, is that I figured out how I want mutable chains to work in Prone. For that to make sense, let's rewind a bit to immutable chains, and some design goals of Prone in general.

From the perspective of someone calling a function, you have excellent protection against surprises. Your callee can make their own modified copies of data, but they have no power to muck with any data in your own scope. For example:

```prone
prn> x = []
prn> push(x, 3)
[3]
prn> x
[]
```

See? The `push` function can't change your copy of `x`, only its own copy. If you want the edited version to replace your copy, that's your responsibility as the caller - you own your scope, nobody else does![^1]

```prone
prn> x = []
prn> x = push(x, 3)
prn> x
[3]
```

Immutable chaining is a syntax sugar that makes some kinds of logic simpler to read. Let's say you want to push a couple values into a list, then sum them.

```prone
prn> []:push(1u8):push(2):push(3):plus()
6u8
```

This is the same as `plus(push(push(push([], 1u8), 2), 3))`, but it's easier to read in this left-to-right way, where the return value of each function gets smuggled in as the first argument to the next function. This is chaining, and it works like normal function calls, with their copy-on-write arguments!

This is nice, but there are times when we want to modify a local object _and_ get a return value out. If `push` puts a new value at the end of a list, `pop` should remove the last value and return it. But then, we kinda need two things out of `pop`: the new version of the list, and the popped value. How should that work?

Last time I talked about this, I was toying with the idea of a special multi-return type, really just a list with a different tag, but I was pretty unenthusiastic about it. There wasn't a lot of harmony with other parts of the language, which makes this feel tacked on, a band-aid for a design problem. I finally found a design I like, but we have to step away from chains for a second, and think more generally about how you might provide _multiple_ mutable params to a callee, while still maintaining strict control over your own scope.

## Building up from basics

Let's say we have a function that chooses a random name out of a hat (represented as a list), removing the name from the hat. It needs to take a second param for the random number generator, which will change state when used. In the example below, the seed for the RNG was [chosen by fair dice roll](https://xkcd.com/221/).

```prone
prn> hat = ["bert", "ernie", "big bird"]
prn> rstate = rng(4)
prn> pick_name(hat, rstate)
["ernie", ["bert", "big bird"], rng(9723)]
```

This function needs to produce three values, which are organized as a list here: the picked name, the updated hat list, and the updated RNG object.

What we'd really like is for it to feel like `pick_name` is just returning the one value, `"ernie"`, and then `hat` and `rstate` magically update in value, all without violating your caller scope ownership. I have a plan. Trust me for the first part, where it sounds crazy.

What if `pick_name` just, by default, returned the picked name?

```prone
prn> pick_name(hat, rstate)
"ernie"
```

On its own, that's not great, because the callee doesn't have a way to feed out new versions of params anymore. But, what if we had a thin little wrapper for objects, which indicated that a parameter was meant to be used not just as an input, but also an output? An `inout` parameter, if you will.

```prone
prn> pick_name(hat, rstate)
"ernie"
prn> pick_name(inout(hat), rstate)
["ernie", ["bert", "big bird"]]
prn> pick_name(hat, inout(rstate))
["ernie", rng(9723)]
prn> pick_name(inout(hat), inout(rstate))
["ernie", ["bert", "big bird"], rng(9723)]
```

Interesting. I'm handwaving a bit, but there's something inside `pick_name` that's able to introspect the params and say, "this param is an inout, I need to change my return signature accordingly."

Let's clarify that. On its own, `inout` is a regular function for creating wrapper objects - it doesn't do any parameter magic, and in fact if you squint at the last example, you'll notice that `hat` and `rstate` weren't updating in caller scope. You can actually make an `inout` in non-parameter code, if for some reason you'd like to. All this does is signal, with types, what you'd like the callee to do, and the callee can fail if it doesn't support what you ask for.

```prone
prn> x = inout([1,2,3])
prn> isa(x, inout)
#TRUE
prn> x:unwrap():isa(list)
#TRUE
```

Something like that, anyways. Wrapped objects are easy to introspect, easy to unwrap, and will play beautifully with pattern match logic at some point.

We get to the magic syntax next: the `@` symbol. This _is_ specific to parameters in a function call, and means "expect the function to wrap return values in a list, and provide new versions of these params in the same order they were passed in."

```prone
prn> pick_name(@hat, rstate)
"ernie"
prn> hat
["bert", "big bird"]
```

Secretly, beneath the sugar, this actually called `pick_name(inout(hat), rstate)`, got `["ernie", ["bert", "big bird"]]`, assigned the latter to `hat` in local scope, and finally evaluated to `"ernie"`.

To people from some backgrounds, this probably sounds wildly overcomplicated. Why not just pass in a mutable copy of `hat` like a normal language? Well, two big reasons:

1. You can debug `pick_name` by calling it explicitly with `inout` params instead of `@` sugar, making it easier to manually and automatically test mutating logic.
2. When you _do_ opt into updating your local copies of things with `@` syntax, this visually stands out. You can tell at a glance where you're trusting a callee function to update your local variables.

All this without giving up Prone's copy-on-write semantics and local scope control. That's pretty neat! We could play in the REPL with pulling different names out of the hat, but without ever mutating our copy of the hat, just to watch the RNG cycle around.

```prone
prn> pick_name(hat, @rstate)
"big bird"
prn> pick_name(hat, @rstate)
"bert"
prn> pick_name(hat, @rstate)
"big bird"
prn> pick_name(hat, @rstate)
"ernie"
```

That's cool. That's empowering. But what does it mean for mutable chaining?

## Harmony at last

Okay, check this out.

```prone
prn> hat->pick_name(@rstate)
"ernie"
prn> hat
["bert", "big bird"]
prn> rstate
rng(9723)
```

Dang! The mutable chain operator is just sugar for passing in the left-hand side as the first arg of the function, but with a `@` on it. That `@` is the only difference between immutable `:` chains and mutable `->` chains. It's still compatible with passing other args as `@` too, if you like. Very neat!

This means we finally know how `pop` should behave on lists. By default, you're not asking for a new version of the list at all.

```prone
prn> pop([1,2,3])
3
```

But you can totally ask for a new version of the list, and you'll get it.

```prone
prn> pop(inout([1,2,3]))
[3, [1,2]]
```

Which combines nicely if you have a list stored in a variable, as you can have multiple pops that are (as usual) evaluated in left-to-right order as a defined behavior of the language.

```prone
prn> my_list = [1,2,3]
prn> plus(my_list->pop() * 10u8, my_list->pop())
32u8
prn> my_list
[1]
```

This is genuinely so cool. It's really nice when you can geek out about something you designed, especially after a long drought of not knowing how to solve it. I'm so happy about this, and even though it'll take awhile before I actually have the opportunity to implement these features, I feel such a relief that I actually have a plan here.

[^1]: And as I always point out, code like this skips the copy, so you get the speed of ordinary in-place mutation. This matters a lot more when make deep edits to a nested structure.