mathjs icon indicating copy to clipboard operation
mathjs copied to clipboard

Move Unit.js into a standalone npm library

Open josdejong opened this issue 6 years ago • 62 comments

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?

josdejong avatar Apr 23 '19 19:04 josdejong

Sounds like a great idea. Not sure how difficult it would be. I'll give it some thought.

ericman314 avatar Apr 23 '19 20:04 ericman314

We could nab the @mathjs namespace on npm for it?

harrysarson avatar Apr 23 '19 20:04 harrysarson

@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.

josdejong avatar Apr 24 '19 10:04 josdejong

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?

ericman314 avatar Apr 24 '19 12:04 ericman314

I think it involves the following steps:

  1. Create a proof of concept, get a clear view on the challenges
  2. 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.
  3. Decide upon a name for the library, create an empty git repo and claim the name on npm.
  4. Think about an API for the library:
    • Creation of units: class new Unit(...) or factory function unit(...)?
    • Dependency injection for the functions like add, multiply, ...
    • Configuration
    • Functions as methods like new x.add(b) or standalone functions like add(a, b) ? Functions as methods, like Decimal.js, Complex.js, and Fraction.js do, 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.
  5. Migrate and implement the new library. Functions, docs, examples, unit tests, ...
  6. Start using the new library in mathjs

josdejong avatar Apr 24 '19 15:04 josdejong

I like the idea of making mathjs into a monorepl with one github repo containing multiple npm packages. Although this approach has downsides too.

harrysarson avatar Apr 24 '19 15:04 harrysarson

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).

josdejong avatar Apr 24 '19 15:04 josdejong

That makes a lot of sense 👍

harrysarson avatar Apr 24 '19 18:04 harrysarson

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.

ericman314 avatar Apr 24 '19 19:04 ericman314

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.

josdejong avatar Apr 24 '19 19:04 josdejong

All finished: https://github.com/ericman314/unitmath

Just kidding, all it does is output Hello, World!

ericman314 avatar Apr 25 '19 03:04 ericman314

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?

ericman314 avatar Apr 25 '19 14:04 ericman314

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

ericman314 avatar Apr 25 '19 23:04 ericman314

@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)

ericman314 avatar Apr 26 '19 14:04 ericman314

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.

josdejong avatar Apr 26 '19 19:04 josdejong

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.

ericman314 avatar Apr 27 '19 03:04 ericman314

I just altered the capitalization in the docs to UnitMath and I like it much better now. (The package name will remain lowercase.)

ericman314 avatar Apr 27 '19 05:04 ericman314

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.

josdejong avatar Apr 27 '19 09:04 josdejong

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?

ericman314 avatar May 20 '19 04:05 ericman314

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.

ajbouh avatar May 20 '19 04:05 ajbouh

Absolutely, you can find the project here: https://github.com/ericman314/UnitMath

ericman314 avatar May 20 '19 04:05 ericman314

That's awesome news @ericman314 :sunglasses: ! You can start a new feature branch based on develop, like feature/unitmath.

josdejong avatar May 20 '19 18:05 josdejong

Thanks, I just added https://github.com/ericman314/UnitMath/issues/13

ajbouh avatar May 20 '19 19:05 ajbouh

@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.

josdejong avatar May 26 '19 14:05 josdejong

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.

ericman314 avatar May 26 '19 15:05 ericman314

I have some time on my hands from Friday onwards and happy to help piping UnitMath into mathjs

harrysarson avatar May 26 '19 15:05 harrysarson

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 .

ajbouh avatar May 26 '19 16:05 ajbouh

Yes, that should be possible.

ericman314 avatar May 26 '19 17:05 ericman314

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?

josdejong avatar May 26 '19 18:05 josdejong

Here we go: https://github.com/josdejong/mathjs/tree/unitmath (almost 200 tests failing at this moment, probably just a few causes)

josdejong avatar May 27 '19 19:05 josdejong