These are chat archives for ramda/ramda

26th
Feb 2017
Denis Stoyanov
@xgrommx
Feb 26 2017 05:59
So I think if u need reverse arguments for reduce or smth u can use flip method
I don't like FPO ( js-sers, please stop it and try to learn haskell/purescript/elm) also I don't like his book about FP
James Forbes
@JAForbes
Feb 26 2017 06:35

I was very excited about "named args" in ramda ramda/ramda#1258. But I've since gone off options objects as args almost entirely (with a few rare exceptions). The argument that more than n args is messy and that putting in an object solves that, is ridiculous. You still have the same amount of complexity, its just less honest about the complexity.

And then "juggling arg order" is a valid argument in theory, but I think ramda et al gets arg order right for 99% contexts. And in those rare cases it doesn't, there's inline lambdas, flip and the placeholder. And you can take your pick based on preference.

I'm not saying FPO is a bad idea, I'm just saying I was someone who had that same excitement that it was solving this big problem. But it only seems a big problem outside of the ramda community. If you are still on the fence about using ramda, it feels like there is still a debate about arg order. I think a lot of people see ramda as just lodash with a different arg order, and they either don't know, or ignore the community, fantasy land, transducers, lenses etc.

And then there's the clear descriptive names argument. More and more I see names as a special kind of code smell that discourages reading / observing / acknowledge the general algorithm. So having named args, at least to me ironically makes the code less clear to read. It means I need to remember the key's the library uses.

It could have some interesting implications on composition though, so I'm not writing it off. But personally I've completely 180'd on the concept.
Not surprised getify is behind it though, he really likes names.

But yeah, I echo what @Bradcomp is saying. I think its great people are trying things.
Keith Alexander
@kwijibo
Feb 26 2017 10:03

ramda et al gets arg order right for 99% contexts

@JAForbes exactly ; there are a handful (or fewer) functions where the argument order doesn't always work (I often define const lookup = obj => key => prop(key)(obj)) but the example of reduce seems a little out of left field

Keith Alexander
@kwijibo
Feb 26 2017 10:08

The argument that more than n args is messy and that putting in an object solves that, is ridiculous. You still have the same amount of complexity, its just less honest about the complexity.

I think it depends - it can help to group arguments together. I most often do this by writing my functions as partially applicable in a specific way, rather than use something like R.curry. eg: const f = (a, b, c) => d => ...

and then sometimes when you end up passing a, b, c around to other functions, it can make sense to group them together as an object (perhaps even a typed object or record, ala daggy / union-type etc)
(but I don't feel the need for functions expecting a Foo to behave in a curried way with respect to the keys of Foo)
James Forbes
@JAForbes
Feb 26 2017 10:27
@kwijibo I create the same function, I call it from usually. Maybe it should be in ramda?
Yeah and your 2nd point is fair. Using some kind of sum type library changes things completely.
Keith Alexander
@kwijibo
Feb 26 2017 10:39
:+1:
James Forbes
@JAForbes
Feb 26 2017 10:39

If I was to be more precise, my main issue with options objects is the flawed argument that its a better pattern because you don't have to update the signature of 100's of functions when you decide to add another property to the object.

But that's kind of backwards to me. The idea that I can change something somewhere in a codebase and it can have a ripple effect automatically on 100's of functions is scary. Its a lot like cascade in css, it seems convenient, but in practice you end up having to write more defensive code. In the case of css your writing super specific selectors that just say "display: none" over and over. And in the case of JS your doing null checks everywhere because its no longer clear what the contract is.

Its also a bit like the fragile base class problem. The moment you commit to options objects as an architecture, you're encouraging most functions in your codebase sharing the same state object, and that means it has to cater all functions, it can't specialize. You can get around that of course, but that is going against the grain (and the aforementioned selling point of options objects).

Also one more issue, just reiterating the naming thing.

By default these days, I name every variable a, b, c etc, I only go back and name variables on a second pass, once I've finished the code, and only if I feel it would make the code easier to follow. I've been maybe twice as productive since switching to this approach. By not trying to decide on names up front. I avoid a lot of navel gazing for the perfect name. Its also a lot easier to come up with a good name when you've finished because its more clear what is actually going on.

Oh, and then name collisions... same object, 2 functions 1 name for two different things. Its so easy to do.

I think sum-type libraries change this and solve all of my issues, and there are other patterns. But yeah there is a subtle danger to extra layers of abstraction, names aren't always a net win.

And all of the above is separate to FPO, this is just me ranting about options objects in general in JS
Ian Hofmann-Hicks
@evilsoft
Feb 26 2017 10:42
:+1: to ALL of that @JAForbes
James Forbes
@JAForbes
Feb 26 2017 10:48
Thanks @evilsoft :)
Brian McKenna
@puffnfresh
Feb 26 2017 10:48
it's a problem in JS because JS lacks the convenience of type-classes
classy optics completely solves the problem of "I have to update all of my functions"
PureScript is the solution
Keith Alexander
@kwijibo
Feb 26 2017 12:18
@puffnfresh is that something you could show with a short example? I'd be interested to see what that looks like
Drew
@dtipson
Feb 26 2017 13:09
Too specifically, or too esoterically, named arguments can also really undermine one's ability to see connections between function signatures, which is a major avenue of seeing simplifications. In languages with type classes
you get this information for free (or well, unavoidably). But if you're making name decisions instead of adding type signature information that feels like a weird direction
James Forbes
@JAForbes
Feb 26 2017 13:56

Just read this article on using prototypical inheritance for tracking history of a state object (which is pretty fascinating):

https://www.webreflection.co.uk/blog/2016/12/23/javascript-proto-state

Which made me wonder if you could compose history transformations with lenses.

And you can!
https://goo.gl/P9aFWw

I don't know when editing histories would be useful, I'm sure it would come up though...

Gabe Johnson
@gabejohnson
Feb 26 2017 14:23
@JAForbes recursive addition and change of a state property during development?
Rick Medina
@rickmed
Feb 26 2017 14:26
I remember an article by j de goes which exposes descriptive parameter names as a code smell or something like that.
James Forbes
@JAForbes
Feb 26 2017 15:20
@gabejohnson sorry not following
where's the recursion?
Gabe Johnson
@gabejohnson
Feb 26 2017 15:27
@JAForbes just if you wanted to add a prop somewhere down in the prototype chain and change it on the way back up.
James Forbes
@JAForbes
Feb 26 2017 15:29

haha I must be missing something, or my brain isn't working :D I'm still not seeing the recursion. Every call to the lens would create a separate branch of the prototype chain, so its arguably wasteful but shouldn't be recursive.

That's a great article you linked by the way.

Gabe Johnson
@gabejohnson
Feb 26 2017 15:30
setProp(‘foo’, { 10: true, 7: false, 3: true, 0: false }, state);
oh. i didn’t look closely enough at the code
Let me look again
And yes it is a great article. Changed the way I think about naming
James Forbes
@JAForbes
Feb 26 2017 15:33
so State.next always returns a new instance. And prev, just returns the prototype, it doesn't mutate. The lens is just using that provided API, so its not mutating an existing prototype, its treating the "parent" prototype as the previous version of the object
its a clever/interesting hack of prototypes
It's a little bit like persistent data structures
Gabe Johnson
@gabejohnson
Feb 26 2017 15:36
It is interesting. Using the prototype chain as a linked list of state updates.
It sort of combines CQRS w/ the structure being updated
so you don’t have to have two structures
How does Object.assign work w/ prototypes?
does it only assign using own properties?
I’d try it myself but am on my phone
Anyway. You could write a function to collapse the chain into one object for snapshotting
Galileo Sanchez
@galileopy
Feb 26 2017 15:42
what is lens composition and how does it work?
Gabe Johnson
@gabejohnson
Feb 26 2017 15:43
@JAForbes one could also use a zipper to return a new state object that had shared structure w/ the parent prototypes
@galileopy R.lensreturns a function and can be composed just like any other if I understand correctly
Gabe Johnson
@gabejohnson
Feb 26 2017 15:48
Very performance lense lib
Syaiful Bahri
@syaiful6
Feb 26 2017 15:49
interesting article @JAForbes
@gabejohnson why it have performance benefit over others lenses lib?
Syaiful Bahri
@syaiful6
Feb 26 2017 15:56
i think it just yet another van Laarhoven lenses.
Gabe Johnson
@gabejohnson
Feb 26 2017 16:28
@syaiful6 I think one reason is it doesn't use Maybes
Syaiful Bahri
@syaiful6
Feb 26 2017 16:31
i dunno what you mean by it doesn't use Maybe s.. Lenses just require functors. it can be any functors.
ramda lenses also doesn't use Maybe..
Gabe Johnson
@gabejohnson
Feb 26 2017 17:18
I was just going off the docs. https://calmm-js.github.io/partial.lenses/#design-choices I don't think they were referring to the ramda len in particular
this delivers all of the benefits of using objects everywhere, right?
can even chuck Reader in there and be implicit about the single object
Brian McKenna
@puffnfresh
Feb 26 2017 23:35
example1 :: forall o. (HasFoo o String) => Reader o String
example1 = flip (<>) " " <$> asks (view foo)

example2 :: forall o. (HasFoo o String, HasBar o String) => Reader o String
example2 = (<>) <$> example1 <*> asks (view bar)