mathjs
mathjs copied to clipboard
Move Unit.js into a standalone npm library
Just floating an idea here: the Unit.js class is a powerful piece of functionality on it's own, separate from math.js. It could be interesting to think about splitting it from math.js into it's own npm library, similar to the libraries Decimal.js, Fraction.js and Complex.js used by mathjs under the hood. Of course Unit.js should keep it's injection of methods like add, multiply, Complex, etc to keep it flexible and integrable).
What would we gain with it?
- Modularity. People may not need mathjs but just need to do some calculations with units.
- Focus. Moving it into a separate library can help focusing. Unit.js has it's own share of complicated problems, and being a part of a larger library (mathjs) doesn't make it easier I think.
@ericman314 do you have some thoughts in this respect?
Sounds like a great idea. Not sure how difficult it would be. I'll give it some thought.
We could nab the @mathjs namespace on npm for it?
@harrysarson I guess we could, though I think it will be more powerful if Unit.js would become a really standalone library, and not sort of a child project still coupled to mathjs.
Sounds like a real challenge, but it feels like the right direction to take it. Where do we go from here? Do we create a new repo?
I think it involves the following steps:
- Create a proof of concept, get a clear view on the challenges
- Find someone who likes to pick up this challenge and becomes the "owner" of the project. Since large part of the code was developed by @ericman314 it would make sense to me if it becomes his library, but it totally depends on if you, Eric, like it and feel like you have enough time to create and maintain the library.
- Decide upon a name for the library, create an empty git repo and claim the name on npm.
- Think about an API for the library:
- Creation of units: class
new Unit(...)or factory functionunit(...)? - Dependency injection for the functions like
add,multiply, ... - Configuration
- Functions as methods like
new x.add(b)or standalone functions likeadd(a, b)? Functions as methods, likeDecimal.js,Complex.js, andFraction.jsdo, have as advantage a nice chaining API. The disadvantage though is that you can't do tree shaking, you have to bundle the complete class with all methods even if you just use a few.
- Creation of units: class
- Migrate and implement the new library. Functions, docs, examples, unit tests, ...
- Start using the new library in mathjs
I like the idea of making mathjs into a monorepl with one github repo containing multiple npm packages. Although this approach has downsides too.
Yes, it's also possible to spin multiple npm packages from the current mono repo.
The reason I'm interested in separating Unit.js is that, like say Decimal.js, it becomes even more powerful if it's focused and standalone. Having a mono-repo typically results in the units of functionality becoming entangled. It is harder to make the "right" decisions for Unit.js when the library when it is a small gear in a big clockwork. Putting it as a separate library can open up a whole new world of opportunities, just like mathjs did when I did split it from the Math Notepad UI.
I see the future of mathjs as being an integrated environment for mathematics in JavaScript: a "hub" merging a lot of different data types together (matrices, units, complex number, ...), and an expression parser making it convenient to work with mathematics in JavaScript. So, moving Unit.js (and also the Matrix classes) out of mathjs would help mathjs getting more focused, and will probably lead to an API that also makes it easier to extend mathjs with more data types (like typed arrays).
That makes a lot of sense 👍
Sure, I'll take ownership. Sounds like a fun adventure. That part I'm unsure how to do would be injecting other types like Complex and Decimal into the new units module.
Cool Eric :sunglasses:
There is no need to know all answers beforehand already, one step at a time.
Have a look at the Unit.js file in the modular_architecture branch, I think the new injection mechanism is much cleaner, can give some inspiration on how we could solve it for the new Unit.js library.
All finished: https://github.com/ericman314/unitmath
Just kidding, all it does is output Hello, World!
I just checked out the dependency mechanism in the modular_architecture branch. It looks great! It kind of reminds me of Angular's dependency injection. However, with unitmath I would like to try and follow the mantra of "do one thing and do it well." Math.js's strength is in managing dependencies and bringing all the different libraries together. I really would not want to have to repeat that mechanism with unitmath, as 99% of use cases in which unitmath will be used alone would not require dependencies on Fraction, Decimal, Complex, etc. I wouldn't want to bundle all of that extra code when it would rarely be used.
Instead, perhaps it would be enough to just allow users (and math.js) to override unitmath's internal add, multiply, round, etc., in order to support different types. unitmath would handle everything with the units, but the user would supply his own types and arithmetic methods for those types. A user's overriding methods could then perform operations between different types using type checking. Do you think that amount of flexibility would be enough for math.js to work with?
I've written a proposed API for the new library. If you like we can continue the discussion there: https://github.com/ericman314/unitmath/issues/1
@josdejong, I've written a proposed API for extending the new unitmath library with custom types. Do you think that this API would work with mathjs? (https://github.com/ericman314/unitmath#extending-unitmath)
Man I love it already @ericman314! The API looks really clean and simple.
I'm glad you go for immutable and factory functions instead of constructors with new :). I think your approach with custom functions add, mul by allowing to optionally override them but have a working solution by default. Setting config looks really elegant!
I'm not sure about the name "extendType". maybe call it "arithmetic" or something? Or simply flatten the config, that may be cleaner and easier to remember, like u = unit.config({ add: ..., mul: ... }).
About number/BigNumber/Fraction, etc: I think that the library does not need knowledge about these specific numeric types, but simply allow passing your own parseNumber function via the config, which enables for example mathjs to parse a string into a BigNumber or Fraction depending on the config of mathjs. I'm not sure how to go about Complex though since right now we have a complex unit VAR in mathjs.
I was thinking about having all functions as methods, which doesn't allow for tree-shaking: that may not be an issue in practice since the number of methods is relatively limited and the implementation is small compared to the rest of the library. So please go ahead with chained methods as described in your proposal :)
Are you still open for finding a nice fancy funny catchy name for the library? If so I will give it some thought.
Thanks for the feedback! You are right that flattening the config would be simpler. No need to overcomplicate things. I actually do find it difficult to use nested config options (think chart.js). The cloning implementation would be a lot simpler, too. Maybe prefix each with "custom", to show that it's a custom operator? So, customAdd, customMul, and so on. I'll think on that.
I also thought about a parseNumber config option, (or maybe we'd call it customParse?) to use with custom types, but then I thought that it might be just as easy for the custom type library to do the parsing, then pass the custom type and unit string into Unitmath. Of course it would be no problem at all to support the parseNumber config option, but since the API support parsing a single string that contains both the value and the units, it might get tricky because the custom parser would need to consume only the numeric portion and leave the units untouched. So we would have that stipulation, otherwise you would have to use the two-argument unit(value, unitStr) when using a custom type.
Yes it's too bad about the complex unit VAR. I'm afraid it will be the first casualty resulting from splitting Unit.js into its own library. I can't think of a good way to include it. It was a bit of a "toy" unit that I honestly don't think gets that much use. And personally I think it even leads to confusion, because a complex quantity is formatted using a real valued number and a complex unit. I would want to be sure 100% whether my quantity was a complex number or not; I would want to see the i.
I'm definitely open to catchy names. I tried variants of Unit.js but they were too similar to existing libraries. I settled on Unitmath because it hints at what the library does--math with units. It's also not too hard to remember, and it's quick to type. Unfortunately, it is painfully boring. To me, it's OK for a really popular library to have a weird, unrelated name (like electron), but I tend to put more trust in smaller, less known libraries if the name actually says what it does.
I just altered the capitalization in the docs to UnitMath and I like it much better now. (The package name will remain lowercase.)
Sounds good going with flat config options. Maybe the "custom" prefixes are a bit superfluous too: any config option you set is per definition custom since it deviates from the default :).
I think you're right about parseNumber: it may be redundant since you can pass any numeric type when constructing a unit. KISS?
It makes sense to simply leave the VAR unit out of the library, and only create it as a custom unit in mathjs.
I totally agree that a boring but clear name is better than something vague. I will give the naming some thought. It's unfortunate that "unit" conflicts with unit testing libraries.
Version 0.2.1 of UnitMath was just released. It is nearing a stable API. I haven't tested it with custom types yet, but trying to integrate it into Math.js might be the perfect opportunity to put it through its paces. What branch should we be basing this work on?
Hope this isn't too far off topic for this, but I have a sort of meta custom type that I've put together for dealing with sums of different unit types. I'd love to contribute it back upstream if there's interest.
Absolutely, you can find the project here: https://github.com/ericman314/UnitMath
That's awesome news @ericman314 :sunglasses: ! You can start a new feature branch based on develop, like feature/unitmath.
Thanks, I just added https://github.com/ericman314/UnitMath/issues/13
@ericman314 v6 is about ready to release, I hope to publish the last beta version today. After that I want to write a blog post about it, work on some nice-to-haves. The real release can be done in one or two weeks from my point of view, but it would be great to have unitmath integrated too.
What is the status of unitmath and when do you realistically think we could have it integrated in mathjs? Is it worth to wait for it? If so, with all pleasure! mathjs@6 is under way for more than a half year now, a few weeks extra is no problem at all. I don't want to put pressure on unitmath though, just get our planning aligned.
UnitMath is getting very close. Since mathjs will be its biggest user at first, having it fully integrated and working would be a good indicator that it has reached a stable api. Otherwise I'm afraid it would just increment minor versions forever without reaching v1. I'll need some help integrating it though, as I'm unfamiliar with mathjs@6's new architecture. A couple weeks might be a little fast, but we'll try.
I have some time on my hands from Friday onwards and happy to help piping UnitMath into mathjs
Will the new architecture make it possible to define units limited to a specific scope?
On Sun, May 26, 2019, 08:47 Harry Sarson [email protected] wrote:
I have some time on my hands from Friday onwards and happy to help piping UnitMath into mathjs
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/josdejong/mathjs/issues/1486?email_source=notifications&email_token=AAABZHJUNRTTOCNDTBENKTDPXKWKFA5CNFSM4HH52ZY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWIIKJY#issuecomment-496010535, or mute the thread https://github.com/notifications/unsubscribe-auth/AAABZHNSPRL5BLGXIZIM5ITPXKWKFANCNFSM4HH52ZYQ .
Yes, that should be possible.
Cool sounds good Eric! Coming Tuesday or Wednesday I can setup a branch starting to import unitmath and replace the old Unit class. From there the three of us (Eric, Harry, me) can work on the branch fixing broken tests and whatever comes along. Does that sound like a plan?
Here we go: https://github.com/josdejong/mathjs/tree/unitmath (almost 200 tests failing at this moment, probably just a few causes)