Closed josdejong closed 1 year ago
Yeah that's a good suggestion, I agree that the different use case for .to()
without arguments could be confusing. There will still be a side effect of using .to(valuelessUnit)
, which is the returned unit has a flag set that prevents automatic simplification. You can also prevent simplification by saying u.toString({ simplify: 'never', prefix: 'never' })
.
I'll make a new method fix()
which implements the parameter-less to()
, and then remove the parameter-less implementation from to
. In the docs I will highlight how calling u.fix()
is equivalent but faster than u.to(u.getUnits())
.
Sounds good. The naming may be a thing: fix
can potentially be confused with the mathematical function to round a number towards zero.
https://mathjs.org/docs/reference/functions/fix.html https://www.mathworks.com/help/matlab/ref/fix.html
I'm reading back through these issues and just now realizing how right you are. .to()
and .fix()
feel very side effect-y.
I wonder if it is better to follow the example of a modern library like the date/time library Luxon. Like unitmath, it also uses immutable types. However, unlike unitmath, and much to its credit, its methods don't cause side effects. I feel like this is extremely important in modern JavaScript. So instead of .to and .fix, we should just have .format()
, which converts a Unit to a string, and parse()
, which converts a string to a Unit. And of course we have all the other Unit operations which return a new Unit. But the two methods format and parse are the only two "interfaces" between the internal representation and human readable forms.
I don't know if this will be possible, especially if we want units to "remember" how they were constructed in order to provide hints as to how they should be formatted. But part of me believes any such "hints" will become a black box that will confuse users when they can't figure out why a unit is being formatted in a certain way.
Agree, having an immutable API is a great thing, it can save a lot of headache.
So instead of .to and .fix, we should just have
.format()
, which converts a Unit to a string, andparse()
, which converts a string to a Unit.
That sounds good and straightforward.
If the units need to "remember" how they where constructed, I think they can save this information themselves in their internal "state", and copy this into any new unit constructed from it. I suppose that a unit can store config like { simplify: 'never', prefix: 'never' }
, and that sounds quite clear to me. I think people will understand if a unit has this config. It maybe even useful to read and alter the config, like:
const a = unit('2 m/s')
const b = unit('2 m/s'), { simplify: 'never', prefix: 'never' })
const c = a.config({ simplify: 'never', prefix: 'never' })
// now, the following three are equivalent:
a.toString({ simplify: 'never', prefix: 'never' })
b.toString()
c.toString()
Just some thoughts.
Yes, upon more thinking, a unit will have to remember its internal state. That way you can do expressions like unit('1 km').to('m').value
to get the number 1000
, which you might want to do your own calculations with.
Having it remember its own formatting config probably goes too far though imho. You could always do opts = { simplify: 'never' }
, and then reuse opts when needed: a.toString(opts)
And, I'm also thinking the default behavior should actually be to not simplify the units, but output the internal representation exactly as it is when calling toString()
with no arguments. I believe that would help increase transparency into the internal workings of the library, and decrease a lot of the mystery that currently happens when formatting as a string. Then to get a simplified output, you could do a.simplify().toString()
or a.toString({ simplify: true })
.
That makes sense indeed.
1.0.0-rc2 is published! The breakthrough I had was realizing that instead of having a separate function and state to prevent simplification, that we should make simplify
itself explicit. So the user has to call simplify
in order to simplify the unit--it doesn't happen automatically any more. That solved so many of the problems I was having, and the API puts the user in control.
o wow, that makes sense indeed! So simple.
From the docs:
It feels a bit like a side effect to use
.to()
to prevent a unit from being simplified. Maybe that could use an explicit function, like.fixUnits()
or.disableSimplify()
orunit('2 m/s', { simplify: false})
or so. What do you think?