Yes. I’m not sure how slow it is in Julia, but pure functional languages do tend to generate more garbage for this reason. Hopefully the compiler can optimize it away in simple cases.
Edit: It’s not deepcopying the whole struct, just the parts that need to point to something new. So if you update a.b.c, it will shallow-copy a and a.b, but nothing else.
> Your natural choice in the "OOP style" is to write a lot of boiler plate to point to each different field you want to get/set.
Your natural alternative to lenses in imperative languages is usually to just store a reference or pointer to the part you want to modify. Like a lens, but in-place.
Yeah, but I’m saying that in 90% of the cases where a functional program would use lenses, the corresponding imperative program would just use references.
Sure, but can you make that imperative program (with pointers and all) as modular/composable? That's the whole point -- lenses are not an end unto themselves; only a tool in service of that goal.
Lenses serve many purposes. All I’m saying is that in practice, the most common role they fulfil is to act as a counterpart for mutable references in contexts where you want or need immutability.
Can the use of lenses make a program more “composable”? Maybe, but if you have an example of a program taking advantage of that flexibility I’d like to see it.
Do check out the links in my original comment above, which explain that the whole motivation behind all this (of which lenses are just a small part) is modularity. Modularity and composability are two sides of the same coin---being able to construct a complex whole by combining simple parts---depending on whether you view it top-down or bottom-up.
Suppose you refactor a field `T.e.a.d` to `T.e.b.d`, for whatever reasons. How many places in your codebase will you have to edit, to complete this change?
Dot access exposes to the outside world the implementation details of where `d` lives, while lenses allow you to abstract that as yet another function application (of a "deep-getter" function) so your code becomes extremely modular and flexible. A good language implementation then hopefully allows you to use this abstraction/indirection without a significant performance penalty.
Yup, that’s basically the idea behind lenses, once you add a few more ergonomic niceties.
The Haskell approach is to take any pattern, abstract it out into a library, and reuse instead of ever having to implement that plumbing again I.e. a very generic get/set_foo which could specialize to specific fields/structures. Following that, you could also write a lenses library in Cpp if you don’t want to redo this for every project.
The point is not that it can’t be done in non-functional languages, but that it’s an uncommon pattern AFAICT; the common approaches result in much less modular code.
Yes. O(1) snapshots are awesome! Persistent datastructures are a monumental achievement.
But that comes at a performance price, and in the end, you only really need persistent datastructures for niche applications.
Good examples are: ZFS mostly solves write amplification on SSD (it almost never overwrites memory); and snapshots are a useful feature for the end user. (but mostly your datastructures live in SRAM/DRAM which permit fast overwriting, not flash -- so that's a niche application)
Another good example is how julia uses a HAMT / persistent hash-map to implement scoped values. Scoped values are inheritable threadlocals (tasklocal; in julia parlance, virtual/green thread == task), and you need to take a snapshot on forking.
Somebody please implement that for inheritable threadlocals in java! (such that you can pass an O(1) snapshot instead of copying the hashmap on thread creation)
But that is also a niche application. It makes zero sense to use these awesome fancy persistent datastructures as default everywhere (looking at you, scala!).
But what’s the benefit of this approach? It seems needlessly expensive, both in terms of computational overhead (walking up and down the state tree) and how much more code it requires.
I guess you gain persistence of your entire app’s state (which makes time travel debugging easier) but that’s all I can think of.
In my experience when applying this architecture to react or svelte, the performance is quiet good, often better than classic alternative approaches (redux, many local useState)
But the main benefit is not only the persistence of the app state, but composable globally consistent state.
With most state management solutions at some point you hit a wall where communicating state changes between far away components is really difficult. You need to manually manage eventlistener lifecycles, route events through the application and convert events into state changes and state changes into events, while not causing cycles or unstable feedback loops or race conditions.
With lenses the state tree is composed declaratively and locally. each component does not need to care if the parent state is locally constructed or coming from further away.
/edit:
Actually using this approach you are not forced to have a single global state but instead each component can simply decide to embed its child components state into its own state or not.
If all components decide to embed their children state you get a single global state. But if all components decide to not embed their children state you get only local state with no communication. But the unified Interface gives you the choice.
Imagine there's a business that can't really enforce whether you walk out without providing compensation. You realize you have the home court advantage on enforcement and guess what, you don't want to pay. It's your browser/wallet and that's your prerogative. But what does that mean about how tempting their goods are? Do we have prerogative to these goods?
Should we live in a world where we only permit business models that require customers pay directly or don't enter at all?
Of course there is a means to enforce payment, paywalls. Ads are a particular model for monetization, it does not mean it is the only one. How about when you want to see a movie, nobody will let you in unless you have bought a ticket. Now of course theaters know that you have paid, but they still say, hey, here are 30 minutes of ads to go with your movie, but then it is then fair for us to show up late.
Meta publishes some interesting data along these lines in their quarterly reports.
I think the most telling is the breakdown of Average Revenue Per User per region for Facebook specifically [1]. The average user brought in about $11 per quarter while the average US/CA user brought in about $57 per quarter during 2023.
Sadly, that's exactly what society does. I can only speak for Australia, but if you have suicidal thoughts then it is a very bad idea to talk to any service even partially funded by the government. ChatGPT, in the absence of strong safeguards of absolute privacy, is as good as anything.
As an example: Mark Cross, who was on the board of SANE Australia, stated that whenever people were put into seclusion would be reviewed. We know now that this was never the case, and still is not being carried out fully. This lauded psychiatrist didn't seem to even known what was happening in his own unit or EDs.
That implies there's some deep truth about reality in that statement rather than what it is, a completely arbitrary framing.
An equally arbitrary frame is "the world and life are wonderful".
The reason you may believe one instead of the other is not because one is more fundamentally true than the other, but because of a stochastic process that changed your mind state to one of those.
Once you accept that both states of mind are arbitrary and not a revealed truth, you can give yourself permission to try to change your thinking to the good framing.
And you can find the moral impetus to prevent suicide.
It’s not a completely arbitrary framing. It’s a consequence of other beliefs (ethical beliefs, beliefs about what you can or should tolerate, etc.), which are ultimately arbitrary, but it is not in and of itself arbitrary.
I don't mean to imply that it's easy to change or that whatever someone might be dealing with is not unbearable agony, just that it's not a first principle truth that has more value than other framings.
In the pits of depression that first framing can seem like the absolute truth and it's only when it subsides do people see it as a distortion of their thoughts.
I think this is certainly part of the problem. There's no shortage of narcissists in the English speaking world who - if they heard to woes of someone in pain - would be ready to gleefully treat it as an opportunity to pontificate down to them about "stochastic processes" and so on, rather than consider how their lives are.
Of course, only thereby, through being quite as superior to all others and their thought processes as me [pauses to sniff fart] can one truly find the moral impetus to prevent suicide.
The randomness of the world and individual situations means no one can ever know for sure that their case is hopeless. It is unethical to force them to live, but it is also unethical not to encourage them to keep searching for the light.
Case studies support this. Which is a fancy way to say, "We carefully documented anecdotal reports and saw what looks like a pattern."
There is also a strong parallel to manic depression. Manic depressives have a high suicide risk, and it usually happens when they are coming out of depression. With akathisia (fancy way to say inner restlessness) being the leading indicator. The same pattern is seen with antidepressants. The patient gets treatment, develops akathisia, then attempts suicide.
But, as with many things to do with mental health, we don't really know what is going on inside of people. While also knowing that their self-reports are, shall we say, creatively misleading. So it is easy to have beliefs about what is going on. And rather harder to verify them.