Git Product home page Git Product logo

pattycake's Introduction

โš ๏ธ Note: this is highly experimental software. Here be dragons ๐Ÿ‰

๐ŸŽ‚ pattycake

Zero-runtime pattern matching. (~10-12x faster ๐Ÿ”ฅ)

Pattycake is an optimizing compiler for ts-pattern that lets you have your cake (expressive pattern matching), and eat it too (zero runtime overhead).

Install

npm install pattycake
Next.js
// next.config.js
const pattycake = require('pattycake');

module.exports = pattycake.next({
  // your next.js config
});
Vite
// vite.config.js
import { defineConfig } from 'vite';
import pattycake from 'pattycake';

export default defineConfig({
  plugins: [pattycake.vite()],
});
Create React App
const pattycake = require('pattycake');

module.exports = {
  webpack: {
    plugins: { add: [pattycake.webpack()] },
  },
};
Webpack
const pattycake = require('pattycake');

module.exports = {
  plugins: [pattycake.webpack()],
};

About

ts-pattern is a great library that brings the ergonomics of pattern matching from languages like Rust and OCaml to Typescript, but at the cost of being orders of magnitude slower.

pattycake compiles ts-pattern's match() expressions into an optimized chain of if statements to completely eliminate that cost. In our initial benchmarks, it outperforms ts-pattern by usually ~10-12x.

In essence, pattycake converts a ts-pattern match() expression like this:

let html = match(result)
  .with(
    { type: 'error', error: { foo: [1, 2] }, nice: '' },
    () => '<p>Oups! An error occured</p>',
  )
  .with({ type: 'ok', data: { type: 'text' } }, function (data) {
    return '<p>420</p>';
  })
  .with(
    { type: 'ok', data: { type: 'img', src: 'hi' } },
    (src) => `<img src=${src} />`,
  )
  .otherwise(() => 'idk bro');

Into this:

let html;
out: {
  if (
    result.type === 'error' &&
    Array.isArray(result.error.foo) &&
    result.error.foo.length >= 2 &&
    result.error.foo[0] === 1 &&
    result.error.foo[1] === 2
  ) {
    html = '<p>Oups! An error occured</p>';
    break out;
  }
  if (result.type === 'ok' && result.data.type === 'text') {
    let data = result;
    html = '<p>420</p>';
    break out;
  }
  if (
    result.type === 'ok' &&
    result.data.type === 'img' &&
    result.data.src === 'hi'
  ) {
    let src = result;
    html = `<img src=${src} />`;
    break out;
  }
  html = 'idk bro';
  break out;
}

Feature parity with ts-pattern

Notes

Fallback / compatibility with ts-pattern

If pattycake is unable to optimize a match() expression, it will fallback to using ts-pattern. This is enabled right now because we don't support the full feature set of ts-pattern.

Inlining handlers

One performance problem of ts-pattern's are handler functions:

match(foo)
  .with({ foo: 'bar' }, () => /* this is a handler function */)
  .with({ foo: 'baz' }, () => /* another one */)

Function calls usually have an overhead, and a lot of the time these handlers are small little functions (e.g. (result) => result + 1) which can be much faster if just directly inlined in the code.

Additionally, a match() with many branches means creating a lot of function objects in the runtime.

The JIT-compiler and optimizer in JS engines can do inlining of functions, but in general with JIT you need to run your code several times or it to determine what to optimize.

So when possible, pattycake will try to inline function expression (anonymous functions / arrow functions) handlers directly into the code if it is small.

IIFEs

When possible, pattycake will try to generate a block of code (like in the example above). But there are times where this is not possible without breaking the semantics of source code.

Roadmap

Right now, the goal is to support the full feature set of ts-pattern, or at least a sufficient amount. After, the ideal is that we compile pattern matching expressions into code that would be faster than what you would write by hand.

pattycake's People

Contributors

aidenybai avatar hdwatts avatar zackradisic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pattycake's Issues

Support SWC for transformation

This may be a bit out of scope for this project, but it may be worth considering also adding an SWC transform instead of just Babel. For big projects especially, Babel can get a bit slow and bulky. Next.js also uses SWC wherever possible, which means that for projects using Next, they don't need to rely on Babel.

Using Vite (V5) requires plugin opts.

import { defineConfig } from 'vite'
import pattycake from 'pattycake'

// typescript wants pattycake.vite(options)
export default defineConfig({
plugins:[ pattycake.vite() ]
})
// the options type HirCodegenOpts just has a bool for chaining so i fixed it as such
export default defineConfig({
plugins:[ pattycake.vite({disableOptionalChaining: true}) ]
})

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.