February 2025 - Month of Qwick Maffs
Qwick Maffs is a project I started a few years ago. The idea was that inputs for numeric values in progams should
always support simple math. Having to open a calculator just to quickly get pi / 6
for some angle value is annoying.
So, I created qwick-maffs to make that really simple, but pretty soon abandoned it once it functioned.
As part of my project to dedicate every month this year to some specific topic, I picked the shortest month to fix this project up a bit.
Added custom operators
The old version had a hard coded list of operators. This puts a fairly hard limit on its potential, so my first task was to address that.
I ended up implementing a generic algorithm for operator precedence parsing called
Shunting yard. It has a couple of quirks, since it just
converts infix notation to reverse polish notation. So it also allows expressions like 4 4 +
. It’s probably possible
to prevent that, but I don’t really see the point. Spitting out an error seems like it would just be a disservice to
the user in our specific use case.
The configuration object can now add or completely replace operators and allows configuring preference, associativity and implementation. They can either be infix, prefix or suffix (I think it should be post-fix, but don’t really care)
Added constants and functions
Before, qwick-maffs could only evaluate numbers and operators. Now it supports customizable constants and functions. After the parser rewrite, adding these was fairly trivial.
Adding units
This was one of the projects I wanted to do that didn’t pan out.
The code is available, but more janky than I’m comfortable with.
Adding units correctly would probably require adding understanding of the units to the operators, which would probably
balloon the complexity more than I want. E.g. 5m + 6m
interacts differently with units than 5m * 6m
, and I don’t
even know if 5m ^ 6m
is a thing at all.
If someone really wants to use the system, they can fork that branch.
Migrating to TypeScript
Before, qwick-maffs proudly had zero dependencies. In theory. In practice, it already had dependencies on tooling like jest and prettier, and used a custom tiny build script to output esm, commonjs and a version that exports into the global namespace.
The downside was that it didn’t export any type info, had to use the horribly ugly jsdoc syntax, and I had to remember to re-run the build script before running tests.
So when I set out to implement units, I first moved to TypeScript for my own sanity. Building just uses tsc, and vitest was used for testing.
It still maintains 0 runtime dependencies.
Bindings for vue
Originally I planned to give multiple framework bindings, but I only had time for the one I’m personally familiar with, vue.
That said, I never made a vue component library before, so this was also a learning experience. Using vite’s library mode was not terrible, but not trivial either. I’m still not sure why it insisted on including dependencies, I only know that a plugin fixed it.
Conclusion
While I definitely learned things, it was a lot less than last month. I started to lose motivation partway through and even started to skip a few days. It didn’t help, of course, that there is nothing really to show of, so nobody else cared either.
But it’s nice to know that this project nobody uses is now in slightly better shape. :P