1. 5
    1. 7

      I had a bad experience with this a couple years ago… not from a technical side but from a social side. This library operates in the FP space but when a few of your coworkers aren’t cut from that cloth, they would just pull .value from your Option & ruin the ‘purity’ ‘discipline’ the other part of the team was trying to enforce. They had a point too as this wasn’t ‘idiomatic’ nor was it ergonomic to use from TypeScript.

      Technically it was good—while I was briefly using it, I was even trying to push for an IRC channel to offer non-corpo refuge from the singular channel of coms, Discord—but we decided it would almost always be better to just use an FP language over what felt like FP lib cosplay. Effect-TS or fp-ts don’t demand you learn category theory or anything like that (& this is a dumb meme that folks repeat which is why it needs to be in FAQs), but many of those that do flock to these libs, at least when I was using it, seemed like they would be happier writing in something else.

      1. 2

        they would just pull .value from your Option & ruin the ‘purity’ ‘discipline’ the other part of the team was trying to enforce.

        Would it be better if .value was instead .#value and therefore enforced private access? Not sure if that’s totally supported in all forms of JS, but the idea of only allowing access to private properties from within the object is definitely a thing in modern JS, so I feel like this is at least a solvable problem. Feels like that’s something this lib can do in order to enforce their own constraints and improve the developer experience on a whole..

        They had a point too as this wasn’t ‘idiomatic’ nor was it ergonomic to use from TypeScript.

        I can definitely agree with this point. Skimming the documentation, I noticed a lot of similarities (at least in theory) to the idea of Rust’s Result types, in which you can return an Ok() or Err() response that determines whether the action succeeded or failed. It’s a really useful pattern in Rust, but that’s generally because Rust itself has syntax support for such a design pattern. JavaScript does not, inherently. Looks like this library is trying to give JS support for the “returning Result” programming paradigm that Rust supports (I forget what it’s called right now), which is a valiant effort! I hope it gains traction, but I’m not really counting on it as it doesn’t jive with the way people usually write JS/TS. However, this could always change…

        1. 2

          private properties

          I don’t know that relying on these all these new-to-spec OO features… private state / encapsulations often seems more bad than good as there are use cases for grabbing the value, it’s just not the way to handle it in a majority of cases & it’s JS so there is bound to be some dunder or otherwise other way to get the value anyhow.

          Rust’s Result

          I feel like it is important to know that Rust was originally built on OCaml & inspired by the ML language family for sum types (such as type Either α β = Left α | Right β) so this didn’t spawn from Rust & the Effect-TS makers seem to be drawing inspiration from the same ML wealth. Having ADTs in JavaScript would make the world a better place than cobbled-together _tag matches on strings, but that’s just not JavaScript or TypeScript are designed (at least at this point… even Dart which swore it wasn’t interested in the FP stuff for years gave into pattern matching + ADTs & we see it came to Java & Python as well). It would be a good addition probably, but feature creep is a real concern for any language which tends to fracture communities than focus. Personally, I would rather see more folks that value these features give PureScript, js_of_ocaml, Melange, LunarML, Idris2, GHC’s JavaScript target, & so on a go rather than trying to shoehorn a bunch of more features into JavaScript so we can have more work in these spaces instead of a bunch of folks succumb to TypeScript while being unhappily trying to make TypeScript more like the languages they would rather be using (which requires technical leads to stop devaluing their front-end teams … I can’t tell you how many projects I have seen with fancy pure Haskell on the back-end & TypeScript on the front-end since it’s just the front-end when the front-end is what the users actually interact with).

          1. 2

            This said, I do think ECMAScript should pick up the RFCs for record & tuple data structures as well as actually implement the tall-call optimization from ES6 since JavaScript is still a compile target that would value these low-level features that are more difficult to replicate the performance characteristics.

            1. 2

              I never understood why V8 yanked TCO.

      2. 3

        TypeScript/JavaScript, the most popular programming language, is still missing a standard library.

        I mean, yeah, but like we have npm and there’s already plenty of well-written libraries to provide datastructures, helpers, etc… I write TS all day and I rarely need more than what’s now available via Array, Object, Set etc and when I do it’s usually a function available in lodash.

        1. 3

          I was just skimming through the code and jumped into https://github.com/Effect-TS/effect/blob/main/packages/effect/src/internal/either.ts.

          My one, simple question, is why in Newton’s name are they manually re-inventing classes?! (All of this “FooProto = Object.assign(Object.create[…]” stuff).

          Is there any point to that at all, or is it just an extreme adherence to the “cool kids don’t use classes because someone on Reddit said that’s OOP and not FP” sentiment? Because, I hate to break it to them, but this is still literally inheritance- it’s just a lot uglier and harder to understand.

          1. 3

            This seems a bit of an unkind interpretation. There are some things you can do with Object.assign that you cannot with inheritance in javascript like multiple inheritance. This is more like mixins/concerns and are not completely equivalent afaik. For example what they do here as far as I understand (from some very quick skimming to be fair) is create effect mixins at runtime. You cannot do that with classes.

            1. 4

              That’s true and fair. And I regret my condescending tone in that comment. I was letting previous experiences on the TypeScript subreddit pre-emptively color my perception.

              It’s true that you can do mixins this way, and I probably jumped the gun in assuming that they aren’t doing that somewhere. Did you see any places where they actually do mix multiple prototypes? I checked a few and only saw code that could be replaced with single inheritance, so I hastily assumed that they were just avoiding the class keyword.

              1. 2

                I hadn’t checked in depth since I was on my phone but now that I’m at my computer and I’m taking a deeper look, I can’t see it very clearly either. However I see some things that I’d have to look deeper to understand to see if they could be represented with single inheritance or if the data flow injects multiple mixins in the objects over time. I can’t really tell at this point:

                Here it seems to add a mixin (Emit?) to a given object. The type parameters makes this very hard to follow, although nothing compared to this. Here is another potential candidate. This one is pretty weird, it does use a class with single inheritance, then Object.assigns this with the given args in the constructor, so this seems to basically implement some kind of adhoc multiple inheritance maybe?. A lot of these places may have interactions that warrant these Object.assign usage. I’m unsure and would have to think really hard about this and understand the whole data flow to say for certain tho!

              2. 1

                Yes, you are quite right. Object.assign copies properties and is not inheritance:

                > class Foo {}
                undefined
                > const foo = Object.assign(Foo, {});
                undefined
                > class Bar extends Foo {}
                undefined
                > const bar = new Bar()
                undefined
                > Foo.prototype.sayHi = function() { console.log("hi"); }
                ƒ () { console.log("hi"); }
                > bar.sayHi();
                VM784:1 hi
                > foo.sayHi();
                VM856:1 Uncaught TypeError: foo.sayHi is not a function
                    at <anonymous>:1:5
                
              3. 1

                My typical experience with FP-ish TS codebases is that the class and new keywords are avoided at all costs, even as you’re writing a function that takes some arguments and returns an object full of functions that close over the arguments.

                My typical experience with OOP-ish TS codebases is that the function keywords is avoided at all costs, even as you’re writing your 100th abstract class with only static methods.

                Even working on teams with people who I consider to be rational, sensible, practical people I’ve seen hilarious resistance to mixing the two styles.

                People want to have an easy answer to code style, and allowing a codebase where you can have both classes and free functions put too much strain on people’s willingness to tolerate ambiguity.

                Then you consider that the amount of encapsulation people state they want and how much they actually desire are two different things. Closures provide the strongest encapsulation possible, it’s literally impossible to inspect it’s state without a debugger, which is all well and good until the precise moment that it isn’t.

                1. 2

                  Even if you don’t like mixing new Foo() and makeFoo() styles (which I don’t, either), you can still just use a non-exported class inside the module and export your factory functions or whatever. It’s something that I have done.

                  But, I’ve also seen people do what you describe and write a factory function that creates a bunch of new functions attached to an object, which makes me absolutely cringe. Totally trashing performance and memory optimization for no reason.

            🇬🇧 The UK geoblock is lifted, hopefully permanently.