DEV Community

Cover image for Smooshing JavaScript
K
K

Posted on

Smooshing JavaScript

Cover image by David on Flickr, cropped by me.

As a JavaScript developer you probably heard about smoosh-gate. Some TC39 people (who are responsible for designing the ECMAScript standard that defines the langauge behaviour of JavaScript) had the idea to rename flatten to smoosh and flatMap to smooshMap. The rational behind this being some websites who use MooTools would break if they don't. These methods are a proposal right now and not part of the standard.

Anyway, I don't know much about MooTools or standards, but I wanted to explain what these functions acutally do.

Why

Most of the time, when programming JavaScript, you are probably messing around with your most favorite functors, arrays and promises. Sometimes they are nested, but you don't care about this. You need an array of numbers and not an array of arrays of numbers or you need a JSON result from your server and not a promise of a promise of JSON result.

What

Promises already come with a then method, that flattens out nested promises.

// loadDataA returns a promise
const dataAPromise = loadDataA();

// dataAPromise resolves to a result with an id that is used to load the next data
// loadDataB returns a promise too
const dataBPromise = dataAPromise.then(result => loadDataB(result.id))

// dataBPromise resolves to the resulting data
// and not the the promise returned from the callback above.
// It's flattened out right away so you only care about the result
const upperCasePromise = dataBPromise.then(result => result.someText.toUpperCase())

// upperCasePromise resolves to the upper case text
// returned by the previous callback.
upperCasePromise.then(upperCaseText => console.log(upperCaseText));
Enter fullscreen mode Exit fullscreen mode

So there isn't much to do here. Some promise libraries like Bluebird come with seperate map and flatMap methods, but mostly you will use then and don't care too much about flattening here.

The solution for this problem in arrays was to add a flatten and flatMap method to arrays. The flatten method replaces every nested array in the array with the content of that nested element, it also removes empty elements.

This function could be written manually with the help of reduce.

const flatten = a => a.reduce(
  (newArray, element) =>
    element instanceof Array
      ? [...newArray, ...element]
      : element !== undefined? [...newArray, element] : newArray,
  []
);

const a = [1, [2, 3, 4], , 5];
flatten(a); // -> [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

We reduce a to a newArray by adding every element to it, if this array is an istanceof Array we add every element of that element to the newArray. (The ...-operator will create a new array for either case instead adding to the existing array, but I think you get the point).

The imperative version could look like that:

function flatten(a) {
  let b = [];
  for (let element of a) {
    if (element instanceof Array) {
      for (let subElement of element) {
        b.push(subElement);
      }
    } else if (element !== undefined) {
      b.push(element);
    }
  }
  return b;
}

const a = [1, [2, 3, 4], , 5];
flatten(a); // -> [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

The flatMap version of this is simply calling flatten on a new array that was emitted by a map.

const flatMap = (f, a) => flatten(a.map(f));

const a = [1,0,7,-3];
flatMap(x => x != 0? 1/x : undefined, a);
// -> [1, 0.14285714285714285, -0.3333333333333333]

const c = [1,2,5];
flatMap(x => ''.padEnd(x, ".").split(""), c);
// -> [".", ".", ".", ".", ".", ".", ".", "."]
Enter fullscreen mode Exit fullscreen mode

The real implementations will probably work like methods and not functions:

// Instead of 
flatten(a.map(x => [1,x]));

// it would be
a.map(x => [1,x]).flatten();

// instead of
flatMap(x => [1,x], a);

// it would be
a.flatMap(x => [1,x]);
Enter fullscreen mode Exit fullscreen mode

Conclusion

Flatten is a rather important action performed many times in every program, so it would be nice if JavaScript came with a built-in version, independent of its final name, lol.

Top comments (28)

Collapse
 
ben profile image
Ben Halpern

As a JavaScript developer you probably heard about smoosh-gate

I had not and now I feel much more informed.

Collapse
 
nickytonline profile image
Nick Taylor

I had suggested a French API name as a joke, but MooTools actually translated their API calls to other languages, including French. 😂 See this thread.

Collapse
 
kayis profile image
K

This is comedy gold.

Collapse
 
yechielk profile image
Yechiel Kalmenson

I'm all for adorable names.

One of my favorite Ruby methods is Array.zip.

Collapse
 
ben profile image
Ben Halpern

Ruby's entire language is adorable. I wish the Ruby community had a mascot like the Go Gopher.

Collapse
 
yechielk profile image
Yechiel Kalmenson

Yeah, I heard Ruby learned a lot from Perl so followed the convention of making after a precious stone.

I'm sure if it was written today it would have had an adorable name and a mascot to go along :)

Thread Thread
 
ben profile image
Ben Halpern

Stones can be cute

And Ruby is a pretty adorable name. I can think of two Ruby devs who named their daughters Ruby. I don't necessarily endorse this kind of commitment but I know it's a thing.

Thread Thread
 
yechielk profile image
Yechiel Kalmenson

Yeah, I met Sean Griffin and his Ruby at rubyconf last year.

I also have a friend who's dog is named Ruby.

Not gofer level cute, but still adorable af

Collapse
 
lesm profile image
Luis Silva • Edited

I want to share our logo from a ruby community we are from Oaxaca México
oaxaca.rb

Thread Thread
 
yechielk profile image
Yechiel Kalmenson

That is a really cool logo!

I'll have to visit someday :)

Thread Thread
 
lesm profile image
Luis Silva

It would be great!

Collapse
 
jbristow profile image
Jon Bristow

How is Array.zip adorable? It's a standard sugar method in a bunch of languages.

Collapse
 
yechielk profile image
Yechiel Kalmenson

I just liked the visual of two arrays getting zipped together, something like a real-life zipper.

Yes, it exists in other languages as well, Ruby is just the first one I came across it, and the one I primarily work with nowadays.

Collapse
 
neonhomer profile image
Kramer

I haven't heard of or thought about MooTools for a very long time (thanks to jQuery).

Seems odd that they would rename a method based on an old library using.

Collapse
 
daniel15 profile image
Daniel Lo Nigro • Edited

Seems odd that they would rename a method based on an old library using.

One of the major design points of the web as a platform is that old sites shouldn't break. While MooTools isn't as popular these days, it was one of the more popular JavaScript libraries many years ago, and a lot of sites still use it.

The issue with MooTools is that it prefers the built-in method (if one exists) over its own method. If it always overwrote the native method, we wouldn't have issues like this. This is also why "ponyfills" never use the native implementation of a function, even if available.

I haven't heard of or thought about MooTools for a very long time (thanks to jQuery).

MooTools was always better than jQuery, though. jqueryvsmootools.com/

Collapse
 
kayis profile image
K

I'm still not sure if they're serious...

Collapse
 
maxart2501 profile image
Massimo Artizzu • Edited

They are.
Of course MooTools' usage in new projects is negligible nowadays, but it wasn't in the past. And there are quite some old sites that still use it.

MooTools had this terrible practice to extend native prototypes. I'm still surprised that it actually gained some favor, but the worst part is that it's been part of Joomla at the time, so it ended up in sites whose maintainers didn't always get to make an educated choice (like jQuery).

In the end, yes, there's a non-negligible amount of sites that would break. Should we let those sites break? Keep in mind that it's not always about abandoned websites, but maybe also sites of small companies or commercial activities that don't have the resources to update their sites.

But alas, we don't have data to back up that.

I still think that letting the TC39 settle for includes instead of contains (because of MooTools, again!) was a slippery slope, and this new issue proved me right.

Now, we do have alternative decent names (like flat or squash), as smoosh wasn't really a serious proposal (very inappropriate from Ficarra, anyway). But I think the adage "We shouldn't break any site when introducing new features" is just an impossible task for TC39. It's reasonable to think that every new feature has a non-zero impact on some existing website/webapp.

I'd like to see real-world data, though.

Thread Thread
 
dinoboff profile image
Damien Lebrun

The problem is not with the TC39 per se. TC39 only reflects the consensus of major vendor; what the point of a standard that will never be implemented; e.g. Array.prototype.values which was turned off in chrome and firefox because it breaks some outdated CMS.

Collapse
 
nickytonline profile image
Nick Taylor

It was mainly a joke I think, but people let it escalate.

I think it made people more aware of TC-39 though.

Thread Thread
 
nickytonline profile image
Nick Taylor

They already have t-shirts 😂

Thread Thread
 
ben profile image
Ben Halpern

🙃

Collapse
 
sompylasar profile image
Ivan Babak

element instanceof Array -> Array.isArray(element), otherwise not iframe-friendly. Refs web.mit.edu/jwalden/www/isArray.html

Collapse
 
kayis profile image
K

Good call.

I just took the first Stackoverflow result xD

Collapse
 
moe64 profile image
Moe • Edited

This is getting more serious!

                 👇👇👇👇👇 This link tho!
Collapse
 
skyrpex profile image
Cristian Pallarés

Insert Wat meme here

Collapse
 
kylessg profile image
Kyle Johnson

I hate to seem really really boring, but I agree.

Collapse
 
nickytonline profile image
Nick Taylor

OK, I found the right name... finally.

Collapse
 
johnpaulada profile image
John Paul Ada

I really hope smoosh() and smooshMap() are jokes LOL