Live data from Hacker News

Lenses in Julia

juliaobjects.github.io

51–60 of 68 posts

Re: Lenses in Julia

#51

Is Julia a general purpose programming language? I mean I did check the web site which contains a "General Purpose" section, yet the articles seem to center around "scientific applications".

it is a general purpose language, but it's happy place is math. Most languages (except Fortan Matlab and R) are very much oriented towards writing web servers/compilers etc, so Julia gets lots of wins in science just by virtue of caring more about math.

Julia is a completely reasonable general purpose language, but getting people to switch generally requires a ~10x better experience, and Julia can't deliver that for general purpose applications.

Re: Lenses in Julia

#52
Now if only the Julia community didn't keep insisting on ligatures and impossible-to-look-up Unicode symbols - the hollow semicolon for compose right to left, seriously?

Re: Lenses in Julia

#53

I have to admit I don’t really understand the point of doing this instead of just obj.a = 2 or whatever.

The other replies covered the answer about immutability well, but I have the further question: why isn't this built into languages as syntax sugar, so that OP's suggested line would work with immutable structures? As a dilettante at programming language design, I have my own toy language. It uses exclusively immutable data structures (C++ "immer"). I present it to the programmer as simple value semantics. `obj.foo[5]…

One of the reasons functional languages like to make mutable code look very different from immutable code is to try to make it clear which is which when reading the code, to help avoid mistakes.

> Is it so offensive that the syntax `obj.a = 2` ends up rebinding `obj` itself?

That does imply that the `obj` binding itself is mutable, so if you are trying for entirely immutable data structures (by default), you do probably want to avoid that.

This is why the syntax sugar, in languages that have been exploring syntax sugar for it, starts to look like:

    let newObj = { obj with a = 2 }
You still want to be able to name the new immutable binding.

Re: Lenses in Julia

#55
post #50

Earlier quoted context omitted.

I think we’re talking past each other. 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 rea…

void set_d(T*);

Re: Lenses in Julia

#56
post #50

Earlier quoted context omitted.

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 rea…

void set_d(T*);

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.

Re: Lenses in Julia

#57
post #18

I have to admit I don’t really understand the point of doing this instead of just obj.a = 2 or whatever.

The difference doesn't matter when you have a shallow structure and can access fields directly and have a few lines of code. But field access does not compose easily if you have a nested hierarchy of objects. 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. Say you get bored of the tedium and want "higher-order" accessors that compose well…

> But field access does not compose easily if you have a nested hierarchy of objects. 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.

This is a self inflicted problem. Make data public and there is no boilerplate.

Re: Lenses in Julia

#58

Earlier quoted context omitted.

The other replies covered the answer about immutability well, but I have the further question: why isn't this built into languages as syntax sugar, so that OP's suggested line would work with immutable structures? As a dilettante at programming language design, I have my own toy language. It uses exclusively immutable data structures (C++ "immer"). I present it to the programmer as simple value semantics. `obj.foo[5]…

One of the reasons functional languages like to make mutable code look very different from immutable code is to try to make it clear which is which when reading the code, to help avoid mistakes. > Is it so offensive that the syntax `obj.a = 2` ends up rebinding `obj` itself? That does imply that the `obj` binding itself is mutable, so if you are trying for entirely immutable data structures (by default), you do proba…

My language doesn't have any other kind; it's not immutable by default, it's immutable only. There are no mutable types or reference semantics, so there's no other kind of type that I need to differentiate. That's my question--why haven't other languages taken this approach? Many newer languages today are full-throated defenses of immutable data structures--why do they still make the mutable structures the easiest, syntactically, to change? Why not the other way around? Julia is fastest with immutable structures--why provide a built-in syntax for complex assignment to mutable types, but then relegate lenses to a library that only FP aficionados will use? We don't want add() and subtract() when we have + and -; why should we live with set() when we have =?

I must be missing it because it worked out pretty nicely in my toy language. Complex assignments are written in exactly the way that people expect them to be. That's why I think it must be about taste or practical consideration--obviously it's possible to write a language like this. But experienced designers don't, presumably because it's a bad idea, and I don't understand what the badness is. Since my language is a toy, I likely haven't hit the practical considerations.

Lenses, to me, feel at home in Haskell where the entire language is a game to see how much theory you can implement in the "userspace" of a tight, maximally-orthogonal FP language. But this is Julia, a monstrously large, imperative, Algol-family language with every possible language feature built-in, intended to be a practical language for analysis by people who aren't programming language experts. Julia's compiler already has knowledge of immutable types which it uses for optimization. Seems like they could do better than lenses if they weren't forced to implement it as a library in the language itself.

Re: Lenses in Julia

#59

Earlier quoted context omitted.

The other replies covered the answer about immutability well, but I have the further question: why isn't this built into languages as syntax sugar, so that OP's suggested line would work with immutable structures? As a dilettante at programming language design, I have my own toy language. It uses exclusively immutable data structures (C++ "immer"). I present it to the programmer as simple value semantics. `obj.foo[5]…

It's an interesting question, why immutability is not built into more languages as the default, so that the most intuitive syntax of assignment produces new values. Without having any expertise in the matter, I'd guess that mutability has the advantage of performance and efficient handling of memory. obj.foo[5].bar.a = 2 An immutable interpretation of this would involve producing new objects and arrays, moving or cop…

That's always the case with immutable data structures; this assignment syntax didn't create that problem. If you used lenses to write 2 into "a", and you expected to get back a new "obj", you would still need to produce all those new objects and arrays. That's just immutable data structure stuff. I'm only asking about the assignment syntax here.

Re: Lenses in Julia

#60

Earlier quoted context omitted.

One of the reasons functional languages like to make mutable code look very different from immutable code is to try to make it clear which is which when reading the code, to help avoid mistakes. > Is it so offensive that the syntax `obj.a = 2` ends up rebinding `obj` itself? That does imply that the `obj` binding itself is mutable, so if you are trying for entirely immutable data structures (by default), you do proba…

My language doesn't have any other kind; it's not immutable by default , it's immutable only . There are no mutable types or reference semantics, so there's no other kind of type that I need to differentiate. That's my question--why haven't other languages taken this approach? Many newer languages today are full-throated defenses of immutable data structures--why do they still make the mutable structures the easiest,…

> But experienced designers don't, presumably because it's a bad idea, and I don't understand what the badness is.

I don't think it's a bad idea, and I don't see anyone else saying that. I did try to give you a couple practical considerations, but I don't think they stop your idea for a toy language from existing or suggest anything you are trying to do is "bad".

> We don't want add() and subtract() when we have + and -; why should we live with set() when we have =?

This question might actually be leading you closer to answers regarding your confusion than you think it is.

One over-simplifying perspective is that imperative languages are the languages that most want operators like + and - and functional languages have most been the languages that want to use add() and subtract() functions. A good functional language wants "everything" to be a function. If you look back at early lisps almost all of them support `(add 2 3)` but not all of them supported `(+ 2 3)`

(ETA: accidental post splice was here.)

Then the functional languages picked up currying, where is useful to refer to the function `(add 2)` as the function that adds two to the next argument and even `(add)` as the function that takes the next two arguments and add them together. In a truly functional language designers often do want `add()` and `subtract()` as reusable, curryable functions more than they want `+` and `-`, because as tools, `add()` and `subtract()` work more like the rest of the languages. As for `set()`, Lisps have almost always only ever had `(let variableName …)` type functions. `=` in most classic functional languages almost always meant an equality check. It's very much imperative languages that gifted us `=` as "assignment" or "set" and then out of consequence of that made equality double (or worse, triple) `==`.

It's only this far after imperative languages have "won" as much as they have, and have proven favored uses for complicated "PEMDAS" parsers that infix operators have become so common. (It's not quite a universal fact, but a lot of functional languages have had much simpler parsers than their imperative language neighbors. Infix operators are a huge complicated thing to parse, if you haven't already noticed in your toy language.)

You denigrate Haskell off hand, but a thing I appreciate that is relevant to all this is that Haskell was also one of the first languages to try hard to strongly merge the two worlds: it supports infix usage of any function, and the infix operators of the imperative world aren't that special syntactically, they are just infix functions. This is also why you'll see a lot of Haskell documentation refer to it is `(+)` instead of `+`, because `(+)` is the "real name" of the function and `+` is just the infix form. Haskell wants an `add()` and `subtract()`, it calls them `(+)` and `(-)`. It supports currying like `(+) 2` can be a function.

A functional programming language sort of wants everything to be a function and operators are a special name of a function. Many functional languages, both historic and current do ask "why do we need + and - when we have (add) and (subtract)?" and even "why do we need = when we have (let)?" (Maybe useful to note too the subtly different imperative versus functional language instincts on where the parentheses go when discussing function names. Imperative languages often as a suffix, almost like an afterthought, and functional languages often surrounding to direct attention inside.)

You suggest several times that lenses are "theory" and "only FP aficionados will use", but lenses are pretty "basic" and boring" from the perspective of "everything is functions". You don't need a lot of theory to understand lenses, even if the goofy sounding name sometimes makes it sound far more complicated than it is.

Which isn't to say that languages can't do better with syntactic sugar, just that one of the reasons this often isn't handled with syntactic sugar from a functional programming perspective is "why would it need to be? it's very simple". Immutable types have a longer history in functional programming languages, so their view of what is "simple" and what should be "syntactic sugar" is maybe obvious to explain from their very different perspective.

There is absolutely a lot of space to keep exploring new syntactic sugar and increasingly better ways for functional languages to take the best ideas of imperative languages. (Again, I appreciate the light humor that Haskell has the reputation today of being the language most drowned in FP theory, but also knowing it has been one of the languages that has done and absurd amount for exploring imperative syntax from a functional standpoint, both in the way that infix operators are just infix syntax for functions, and in things like do-notation.)

Please keep playing with your toy language and imperative/mutable syntax for immutable data structures, I think that's great. I've done similar experiments in my own toy languages. I think the answer to why "big languages" haven't done it yet, isn't because it is a "bad" idea, but because it is a matter of perspective. Most functional languages don't want imperative syntax or don't want functional/immutable things to look like imperative/mutable syntax. Again, not because it is "bad", just because they have very different family trees.

Post reply on HN