Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readme doesn't explain what the library does #24

Open
augnustin opened this issue Jun 16, 2015 · 7 comments
Open

Readme doesn't explain what the library does #24

augnustin opened this issue Jun 16, 2015 · 7 comments

Comments

@augnustin
Copy link

The readme.md file does a pretty good job introducing issues that arise while writing functionnal js. It really gives desire to avoid those.

But in the end, I haven't picked up:

  • what methods the library exposes
  • if it is ECMA6 only
  • how to get started.

For instance, I use Lodash. Are there any reason I should consider moving to trine?

@barneycarroll
Copy link

The docs (linked from the README) list all the methods and show you how to use them.

Trine needs ES7 (via Babel, with runtime included and experimental flags). This enables it to be far more convenient than Lodash because you can then chain methods without using wrappers. The README shows an example of an array that's filtered and then mapped (native array methods), but then has a Trine method (flatten) applied to it using ES7's bind operator. This feature (plus ES6 iterators under the hood) mean you get all the benefits of Lodash's chaining without having to wrap or unwrap your data — you can call the Trine method on the data object directly :D

The key gain is that by using the features of ES7 idiomatically, your code reads far better in source (and it's far easier to reason about what you want to write without thinking about how to write boilerplate), but compiles down to something similar to Lodash for use in ES5.

@augnustin
Copy link
Author

Thanks for feedback. I opened the issue not only to get the info myself, but more to make a feedback on what can a newcomer understand from landing there and what IMHO could be nice to explain more in detail. :)

@jussi-kalliokoski
Copy link
Owner

If there's any ideas on how to improve the README in this regard, I'd be more than happy to take PRs. :) I'm not quite sure how to communicate this information in the README myself. :/

@jussi-kalliokoski
Copy link
Owner

For instance, I use Lodash. Are there any reason I should consider moving to trine?

As for this question, given that Trine is built on the bind syntax proposal that may or may not ever land to JavaScript (although it seems unlikely to me that it wouldn't), production usage is not advised, and should be considered carefully. You might end up being bound to a specific version of Babel if you depend on the bind syntax. That's part of the reason why I didn't add very specific instructions on how to easily get set up either, because you should know what you're doing as well as possible if you decide to take Trine into production use.

@barneycarroll
Copy link

may not ever land to JavaScript

@jussi-kalliokoski that would be hilarious. "The functional programming library that Javascript definitely deserves, but can't actually run" – that should keep the haters happy ;)

@jussi-kalliokoski
Copy link
Owner

@barneycarroll hahah, yes. 😆

@jussi-kalliokoski
Copy link
Owner

Of course, there's the performance benefits as well. For example the case that's in the README, getting the first 15 items of a large product catalogue, sorted by price.

Here's a benchmark of doing that for a product catalogue of 1 million items:

"use strict";

import { quickSort } from "trine/iterable/quickSort";
import { head } from "trine/iterable/head";
import { to } from "trine/iterable/to";

function inMilliseconds () {
    const seconds = this[0];
    const nanoseconds = this[1];
    return seconds * 1e3 + nanoseconds / 1e6;
}

function measure (samples) {
    const times = [];

    for ( let i = samples; i > 0; i-- ) {
        const start = process.hrtime();
        this();
        const elapsed = process.hrtime(start);
        times.push(elapsed::inMilliseconds());
    }

    times.sort((a, b) => a - b);
    const medianTime = times[Math.floor(times.length / 2)];

    console.log("%s took %sms", this.name, medianTime);
}

function * randomProducts () {
    while ( true ) {
        yield {
            price: Math.random() * 1000,
        };
    }
}

const SAMPLES = 1000;
const PRODUCTS = 1000000;

const products = randomProducts()::head(PRODUCTS)::to(Array);

function native_sort_15_first_items () {
    return products
        .slice() // copy the array to avoid manipulating the original
        .sort(function (a, b) { return a.price - b.price; })
        .slice(0, 15);
}

function trine_quicksort_15_first_items () {
    return products
        ::quickSort(function (b) { return this.price - b.price; })
        ::head(15)
        ::to(Array);
}

native_sort_15_first_items::measure(SAMPLES);
trine_quicksort_15_first_items::measure(SAMPLES);

The results on my computer were as follows:

native_sort_15_first_items took 1842.314449ms
trine_quicksort_15_first_items took 715.955531ms

(The benchmark took around an hour to run for me, so might want to adjust the constants if you want to run it yourself).

As you can see, Trine is almost 2.5x as fast in that example compared to the native equivalent (and AFAIK, lodash, underscore and Ramda all use the native sort internally so would have similar or worse performance characteristics as the native version). However, if you start decreasing the catalog size, you'll quickly notice that the native equivalent becomes faster - this is because of the current overhead of iterators due to not being provided natively but by pretty complex state machine logic in regenerator.

And the current quicksort implementation in Trine is actually rather naive and could be optimized to be much faster, and also at some point when engines start optimizing generators and Trine doesn't need to be compiled anymore, the difference will likely become even greater.

Unlike with other utility libraries, you usually don't even have to be thinking about performance and computational complexities with Trine, as just naturally spelling out what you want will most likely be the fastest way to perform the operation. Using plain old ES5, you'd have to hand-write a sort implementation that only does precise sorting for the first N items to get the same performance you get with Trine out of the box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants