Looking for beta testers

An exciting new compiler optimization landed on our master branch today, and we’re looking for adventurous souls to test it out!

The PR in question is https://github.com/purescript/purescript/pull/3915, which has been waiting in the wings for a while now for the right time to be merged. This optimization selectively generates variables for instantiated type class members in a parent scope, so that instead of this:

var ap = function (dictMonad) {
    return function (f) {
        return function (a) {
            return Control_Bind.bind(dictMonad.Bind1())(f)(function (f$prime) {
                return Control_Bind.bind(dictMonad.Bind1())(a)(function (a$prime) {
                    return Control_Applicative.pure(dictMonad.Applicative0())(f$prime(a$prime));
                });
            });
        };
    };
};

you’ll see this:

var ap = function (dictMonad) {
    var bind = Control_Bind.bind(dictMonad.Bind1());
    var pure = Control_Applicative.pure(dictMonad.Applicative0());
    return function (f) {
        return function (a) {
            return bind(f)(function (f$prime) {
                return bind(a)(function (a$prime) {
                    return pure(f$prime(a$prime));
                });
            });
        };
    };
};

I expect this to have positive effects on bundle sizes and run-time performance for many projects, particularly ones that make heavy use of classes and eta-reduced curried functions. For example, I cooked up this version of the benchmark graph from @PureFunctor’s recently-announced uncurried-transformers project:

But this is a big change internally, and causes code to be evaluated in a different order (instance members can now be evaluated earlier than the expressions that use them). So this message goes out to anyone who wants to help us find any lurking issues related to this before we get around to releasing 0.15.3.

Simply use any prerelease build >=0.15.3-1, be sure to wipe all of your output code, and let us know here or on GitHub about any issues you encounter. If things go well for you, a note here in this thread would also be appreciated, to give us confidence that enough people have tried it out.

Thanks for helping out!

8 Likes

I switched Real World Halogen over, and it shaves 3kb off the bundle (505kb → 502kb; the project doesn’t make heavy use of classes, but it’s MTL-based). It’s a Halogen app so it’s hard to notice differences in performance; there wasn’t any noticeable jank before, and there isn’t any now.

5 Likes

I tested it with one of my bigger projects.

The project is using halogen-hook and I’m not sure about performance (seems to work the same way as before - but performance is not really a concern here).

It reduced the bundled (esbuild) code-size from ~499kb to ~465kb - so quite good IMHO - thanks for the continuos improvements :heart:

7 Likes

Hello!

I tried it out on wags. There seems to be an issue in the generated JS:

var 4xIsSymbol = {
    reflectSymbol: function () {
        return "4x";
    }
};
var 2xIsSymbol = {
    reflectSymbol: function () {
        return "2x";
    }
};

I don’t know the internals of the PR, but my guess is that IsSymbol sym takes the symbol name to create the variable name, and because a JS variable name can’t start with a number, an error happens.

6 Likes

Ah, great catch. Thanks for the report!

3 Likes

The 2x/4x issue should be sorted out in 0.15.3-2. I took the liberty of compiling wags and while I haven’t tested execution, there are no more syntax errors in the output.

3 Likes

I ran 0.15.3-3 on CollegeVine’s production codebase. Some light manual testing did not uncover any functionality issues, and neither did spot-check of non-minimfied code. All automated tests passed. We have a quite exhaustive test suite - some tests written in PureScript and running on simulated DOM, as well as Selenium-based integration tests running on FireFox.

Out of our 96 bundles, 2/3rds saw a size increase by a trivial amount (hundreds of bytes), but a few of the most complicated ones shrunk by a few kilobytes. The mean size delta was -157 bytes (pulled by the shrunk ones), while the median was +485.

5 Likes