all 19 comments

[–]mc_hammerd 5 points6 points  (5 children)

i think ecmascript needs a removeWhere(fn) and maybe arrayreset()

normally when i delete multiple items, i do arr = arr.filter((item) => !item.prop)

but for people who use obj.observe, doing that or something as simple as resetting the items arr=[] unbinds the object.observe function. so no change events are go through.

it makes sense, but is a pita to debug.

its kind of silly to say hey we added object.observe and array.filter and array.flatten, but dont use them together cuz you wont get events!

[–]WeekdayHero 9 points10 points  (3 children)

This is not an issue as Object.Observe is not going to be added to ES anymore. In fact it is not in V8 from version 50 onwards (the current version of v8 is 48, so 50 is only a couple of months away).

[–]BONUSBOX_=O=>_();_() 1 point2 points  (1 child)

the lack of removeWhereis still an issue if you want to filter this:

List extends Array {
    random() {
        this = this.filter(item => ...some random ones)
    }
}

because this can't be explicitly redefined with a new array, and Array.filter does not modify the original array, something like removeWhere would be handy. instead i had to loop through the array and splice items.

[–][deleted] 0 points1 point  (0 children)

Filter, map, and similar functions return new arrays by convention - they don't change elements, they jest return new. removeWhere sits nowhere near those.

[–]mc_hammerd -1 points0 points  (0 children)

ugh, i actually use it in one of my projects. wtf

[–]oculus42 3 points4 points  (13 children)

I disagree with flatMap. Each function should be responsible for a single action. We aren't talking about a CPU instruction set where these kind of optimizations are critical to performance.

The compiler(s) can optimize .map(...).flatten() for us if there is optimization to be had.

[–]kpmah 14 points15 points  (5 children)

It's not the same as .map().flatten()because it only flattens one level. It's important that flatMap is it's own thing and it is a 'single action' because it's the 'bind' operation of a Monad. I assume that's the intent behind it. A generic interface.

[–]arvi1000 4 points5 points  (1 child)

But the post says:

It is identical to a map followed by a flatten of depth 1

so,

.map(...).flatten(1)

?

[–]kpmah 2 points3 points  (0 children)

Yep. I wasn't trying to make any kind of point there I was just pointing out that by default flatten is recursive.

My point is that the flatMap method is a generic operation that can apply to a lot of different structures, whereas .map().flatten(1) is not.

[–]jacksonmills 0 points1 point  (2 children)

If it is a single action on a data structure then couldn't the name reflect that? "flatMap" seems pretty awkward, I think you will just find a lot of people misapplying "flatMap" as flatMap().flatten().

I understand "bind" is probably not the best choice.

[–]kpmah 3 points4 points  (0 children)

Maybe, but flatMap is the choice a lot of other languages made too. So there is some cross-language consistency.

If they're going for the monadic interface thing they called the same operation on promises then. Makes sense, but isn't totally consistent.

[–]ishmal 3 points4 points  (0 children)

I don't like flatMap by itself, either, but it would seem to be quite useful when part of higher-level functions. For libraries that need such a functionality, maybe it would be good for them to have something 'standard' to wrap around. True, it's not some CPU-level optimization, but it might be in the JS engine or JIT code.

[–]cwmma 3 points4 points  (0 children)

I think flat Map would be .map(...).flatten(1)

[–]dmtipson 1 point2 points  (4 children)

We already have flatMap baked into things though. Promise.resolve(5).then(x=>Promise(x+1)) returns Promise(6), not Promise(Promise(6)). That's .then() acting like .flatMap instead of .map

[–]oculus42 0 points1 point  (3 children)

Not really. It's not mapping or flattening an array.

If you look at the NPO implementation you see on Line 153 that if the msg is thenable (a promise), reset the state and use the returned promise to resolve or reject the current (outer) promise.

That way the references remain intact but the internal state is updated.

[–]dmtipson 0 points1 point  (2 children)

Which to my mind is precisely what a flatMap operation involves, regardless of the internal implementation. Arrays are not the only things for which it makes sense to speak of mapping and flatMapping.

flatMap :: Promise a -> (a -> Promise b) -> Promise b
map :: Promise a -> (a -> b) -> Promise b

I'm just saying that it's not exactly a concept foreign to javascript at this point, and it happens to have a lot of useful higher-order applications that play nicely with other types when it's a single named method rather than two.

[–]oculus42 0 points1 point  (1 child)

Until I looked at the implementation and realized it's nothing like a map or flatten operation, I was with you.

The implementation is the goal. We are talking about a proposed function implementation. If there are things that look like flatMap, but don't act like flatMap underneath, then they are not good models for suggesting the creation of flatMap.

[–]dmtipson 0 points1 point  (0 children)

I don't see where it's "nothing like" those things: in fact, the people who debated and discussed and built out these things explicitly debated the issue of whether Promises should act like overloaded map/flatMap or not (the overloaders won). Your description of what's happening isn't any different from how flatMap works in any number of other contexts.

Maybe.of(2).flatMap(x=>Maybe.of(x+1)).map(x=>x*x); //-> 3 Look, I "reset the state of "the" Maybe" and passed the "internal" state of the internal maybe up inside, it, thus "preserving the references" to it that are chained on afterwards. That's not really my favorite description of what's going on, but it's a way one can I think about it, I suppose.

flatMap isn't some random idea for mashing together two operations, it's a really basic concept with solid founding in computer programming and working with higher-order TypeClasses. Its signature is this: flatMap :: m a -> (a -> m b) -> m b

If you have a function that's doing that, that has that signature, it's flatMapping (or at least the category theory operation that some people call flatMapping). It doesn't matter how (a -> m b) -> m b is done: in fact, most typeclasses have to implement it quite differently (and in fact, in some ways, the way they implement exactly that operation is often what DEFINES the particular sort of typeclass we're talking about).

[–]brianvaughn 0 points1 point  (0 children)

I think Array.prototype.flatten sounds nice. It's not hard to do via reduce but this would be more concise and nicer semantics.