Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Power/exponent expression support #684

Open
scottkellum opened this issue Mar 13, 2013 · 59 comments
Open

Power/exponent expression support #684

scottkellum opened this issue Mar 13, 2013 · 59 comments

Comments

@scottkellum
Copy link

@scottkellum scottkellum commented Mar 13, 2013

Thoughts on adding native support for exponents in Sass expressions? While a simple loop can easily calculate positive integers, other values are more difficult to calculate. It can be done but not efficiently in pure Sass.

Preferred syntax would be like Ruby:

5px**2

A function could work as well:

pow(5px, 2)
@robwierzbowski
Copy link

@robwierzbowski robwierzbowski commented Mar 18, 2013

I very much like the ruby syntax. If there's an internal conflict that makes that difficult, most people understand the caret syntax too:

5px^2

@Snugug
Copy link

@Snugug Snugug commented Mar 18, 2013

Would that be 25px or 25pxpx?

On Mar 18, 2013, at 3:40 PM, Rob Wierzbowski notifications@github.com wrote:

I very much like the ruby syntax. If there's some internal conflict that makes that difficult, most people understand the carat syntax too:

5px^2

Reply to this email directly or view it on GitHub.

@robwierzbowski
Copy link

@robwierzbowski robwierzbowski commented Mar 18, 2013

That is how Sass deals with a manual square right now. Obviously the intention would be for it to be 25px.

@nex3
Copy link
Contributor

@nex3 nex3 commented Mar 22, 2013

What's the use case for non-integer exponents? I'm not sure we want to move towards adding a full complement of mathematical operations in core Sass. That seems like a good thing for extensions to do.

It would be pretty confusing if pow(5px, 2) didn't return a result in square pixels.

@scottkellum
Copy link
Author

@scottkellum scottkellum commented Mar 22, 2013

@nex3 I want to remove the need for Ruby in the modular scale extension. While CodeKit, Mixture, and other tools do support extensions, the process is far too complex for a significant portion of that audience. Distributing Ruby extensions via Bower is also problematic.

to be clear, pow(5px, 2) = 25px and pow(5px, 2.5) = 55.901699437px. Your example would result in square pixels. I have found half units to be useful when setting type on an exponential(modular) scale and the scale moves too quickly in that area.

@nex3
Copy link
Contributor

@nex3 nex3 commented Mar 22, 2013

@nex3 I want to remove the need for Ruby in the modular scale extension. While CodeKit, Mixture, and other tools do support extensions, the process is far too complex for a significant portion of that audience. Distributing Ruby extensions via Bower is also problematic.

What makes this so difficult? Ruby-based extensions are never going to be completely avoidable for complex operations. I'd like to make them easier to use rather than essentially unusable.

pow(5px, 2) = 25px

Your example would result in square pixels.

These two statements seem contradictory.

I have found half units to be useful when setting type on an exponential(modular) scale and the scale moves too quickly in that area.

What do you mean by "half units" and "the scale moves too quickly"?

@robwierzbowski
Copy link

@robwierzbowski robwierzbowski commented Mar 22, 2013

Half units == decimal exponents, and "the scale moves to quickly" is behavior specific to the modular scale extension.

I think the main point is right now we can make an exponent function in an extension and distribute it, but it would be more convenient to have a native-to-the-parser syntax. Exponents are one step up from basic math, and a native syntax would encourage authors to use and experiment with them. So the decision is: should exponents be in Sass, or should they be provided by a function in an extension?

@nex3
Copy link
Contributor

@nex3 nex3 commented Mar 22, 2013

We're definitely not adding syntax support for exponents; the functionality isn't broadly applicable enough. We could potentially add a function for it, but there is a line of niche uses past which we won't add math functions. Should we add root functions? Logarithms? Trigonometry?

I'd much rather see a math package that encapsulates all of these and keeps them out of the core set of functions. Then they're available for libraries that need them, but they don't clutter up the default namespace with functions that just aren't useful to most users.

@robwierzbowski
Copy link

@robwierzbowski robwierzbowski commented Mar 22, 2013

That's reasonable. @scottkellum, want to collab on a Sassy Math package?

@Snugug
Copy link

@Snugug Snugug commented Mar 22, 2013

@robwierzbowski Kinda like https://github.com/scottkellum/sassy-math 👅
If we're missing something, happy to add more.

@robwierzbowski
Copy link

@robwierzbowski robwierzbowski commented Mar 22, 2013

Ha, well look at that. Consider it 'd

@nyarly
Copy link

@nyarly nyarly commented Aug 22, 2014

If the syntax doesn't support at least exponentiation - how does complex math get dealt with in libsass? Most of the examples that come to mind could be calculated by hand and assigned to a variable, but isn't that true of most Sass numerical operations?

@Snugug
Copy link

@Snugug Snugug commented Sep 23, 2014

I recently started to work deeply with color spaces and in order to build the w3c relative luminance function, a decimal power is required. This is non-trivial to calculate by hand and while having a Ruby function would allow this to work, it would do so at the loss of cross-compiler compatibility.

@torkiljohnsen
Copy link

@torkiljohnsen torkiljohnsen commented Dec 1, 2014

I was just working on the exact same thing @Snugug. At some point an x^2.4 was needed for almost all colors in that calculation. Using the Sass-native pow() function from https://github.com/terkel/mathsass 10 times resulted in a serious slowdown in compile speed. This was the only Sass-implementation I was able to find for decimal exponents.

My purpose with this was automatic color adjustment to ensure AA-compatible color contrasts. The contrast-calculating function was the one doing the ^2.4.

I managed to cook up something a bit faster, but still very slow:

x^2.4 = x^2 * x^0.4 
x^0.4 = x^4/10 = x^2/5 = (x^1/5)^2

In other words:
x^2.4 = x^2 * (x^1/5)^2

x^1/5 = the fifth root of x.

I proceded to implement an nth-root-function: (note the hard-coded $guess!)

@function nth-root-estimate($number, $guess, $n) {
  @return 1/$n * (($number/pow($guess, $n - 1)) - $guess);
}

@function nth-root($number, $degree, $precision: 5) {
  $guess: 2.7;
  $previous-guess: 0;

  // While precision has not been met, keep guessing
  @while round($previous-guess * pow(10, $precision)) != round($guess * pow(10, $precision)) {
    $previous-guess: $guess;
    $guess: $guess + nth-root-estimate($number, $guess, 5);
  }

  @return $guess;
}

@torkiljohnsen
Copy link

@torkiljohnsen torkiljohnsen commented Dec 1, 2014

This is the first time I have come to the sad conclusion that I should have been using less :(

@torkiljohnsen
Copy link

@torkiljohnsen torkiljohnsen commented Dec 1, 2014

Here's the code I was testing out. See "Usage" at the bottom, and see the 2.4-pow() on line 9.

http://madebymike.com.au/writing/accessible-contrast-with-less-and-sass/

@torkiljohnsen
Copy link

@torkiljohnsen torkiljohnsen commented Dec 2, 2014

For now, to achieve better speed, I hard-coded a list of pre-calculated 5th root numbers for the color numbers in question. Looking up an item in a list that is 255 items long is a lot quicker than calculating the 5th root.

@torkiljohnsen
Copy link

@torkiljohnsen torkiljohnsen commented Dec 2, 2014

@scottkellum
Copy link
Author

@scottkellum scottkellum commented Dec 2, 2014

FWIW I think we should keep this discussion focused on arguments for or against the Sass feature in question (native pow() function). Examples of use cases are helpful arguments for this but details and work arounds to implement specific use cases are likely not helping the debate here.

@torkiljohnsen The Ruby dependency thread on sass-a11y may be a better place for these workaround suggestions.

To sum up arguments for a native pow() function in Sass:

@jtangelder
Copy link

@jtangelder jtangelder commented Dec 29, 2014

+1 for this feature, very needed for some easing calculations.

@jakob-e
Copy link

@jakob-e jakob-e commented Jan 19, 2015

+1

I can't think of a reason why "basic" math functions should not be native like in Javascript nor functions for conversion like deg(number/deg/rad/grad/turn) – now we have to do it by hand like this .

I fail to see why abs, max, ceil and floor are fine – but not pow, sqrt, sin, cos... and how adding them will clutter up the default namespace for "most users".

Sorry if it sounded grumpy :-)

PS. The math functions in Less

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 24, 2015

👍

I also want to use decimals within pow for a modular scale lib I'm working on.

@jakob-e makes some pretty compelling arguments as well.

It's goofy Sass doesn't support math.

corysimmons pushed a commit to 2metres/typographic that referenced this issue Mar 25, 2015
Will base Sass off actual modular scale when it supports it natively: sass/sass#684
@davidkpiano
Copy link

@davidkpiano davidkpiano commented Mar 25, 2015

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 25, 2015

@davidkpiano So math-pow(12, 3.4) returns 4668.92127 without having to get Compass and all that stuff involved??

@davidkpiano
Copy link

@davidkpiano davidkpiano commented Mar 25, 2015

@corysimmons That's correct. No dependencies. Gotta love Maclaurin series 😄

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 25, 2015

Awesome, thanks for this. I'll try to implement it tonight.

@torkiljohnsen
Copy link

@torkiljohnsen torkiljohnsen commented Mar 25, 2015

What @jakob-e said. Look to Less.

@Snugug
Copy link

@Snugug Snugug commented Mar 25, 2015

I realize a conversation I had with @nex3 at SassConf about this somehow didn't make it in to this thread.

She said that she would be much more likely to be OK with more Sass-land functions (including a full math package) once #1094 landed and they could be bundled as optional libraries someone could pull in. Actually, on second read, she seems to mention it in this commend above. Either way, right now there is a very stable Ruby implementation of advanced math functions, and now that custom functions has landed in node-sass, expect one for that too.

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 25, 2015

I don't mind the idea of bypassing Compass and @importing custom Ruby packages to Sass libs, but I didn't see anything in #1094 that had anything to do with this. Maybe I overlooked it.

I'll try to see if I can get memoization working with decimal exponents and if I can't then I'm not going to keep worrying about it. Sass can do it's slow thing.

@Snugug
Copy link

@Snugug Snugug commented Mar 25, 2015

@corysimmons Namespaced imports in that issue.

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 25, 2015

Would that import Ruby-ish functions or just standard Sass libs? If the latter it wouldn't be of much use to us.

@davidkpiano
Copy link

@davidkpiano davidkpiano commented Mar 25, 2015

@jakob-e Oddly enough, the (undocumented) functions pi() and e() exist in Ruby Sass, which return the respective constants. I can't really remember how I stumbled upon those.

$pi: pi(); // 3.14159
$e: e(); // 2.71828

@scottkellum
Copy link
Author

@scottkellum scottkellum commented Mar 25, 2015

@Snugug @nex3 I understand that Sass can easily be extended with Ruby, as a lib extension, or through Eyeglass. However I think the argument this thread is trying to make is that this is important as a core feature of the Sass spec. There are environments where deep level Sass extensions are difficult and they dramatically increase the complexity of installing and distributing code.

@scottkellum
Copy link
Author

@scottkellum scottkellum commented Mar 25, 2015

@davidkpiano
Copy link

@davidkpiano davidkpiano commented Mar 25, 2015

@scottkellum EDIT: Apparently Compass passes functions even without being imported.

@scottkellum
Copy link
Author

@scottkellum scottkellum commented Mar 25, 2015

@davidkpiano Yeah, Sassmeister and Codepen both use Compass.

EDIT: It doesn’t matter if you import Compass, Ruby functions are passed through without imports. If you are compiling your Sass with Compass then all the Ruby extensions are available by default.

@Snugug
Copy link

@Snugug Snugug commented Mar 25, 2015

@scottkellum agreed, but until it's available, there are fairly easy to use plugin implementations.

@corysimmons Take a read of that thread. It's a total re-write of Sass's import system.

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 25, 2015

I read it, and a few of the linked threads, still seemed like it was just referring to how it imports Sass files, not exposing Ruby functions. I'm probably stupid - been up all night.

I'd still agree with @scottkellum that core math functions (like support for exponents) should probably be part of Sass core - especially if it's going to take another year or so for the import system to get rewrote.

You can always pull core stuff out to modules once the import-rewrite PR goes through, so even if you were just to add these math functions in now, and then in 2-3 years when this goes through you could just take them out (along with a bunch of other stuff to make Sass more modular).

@Snugug
Copy link

@Snugug Snugug commented Mar 25, 2015

The idea is, once namespacing is available, if I understood @nex3 correctly, is that more core functions could be shipped as optional imports so as to not pollute the namespace.

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 25, 2015

Yeah that'd be cool/optimal.

Again though, I wonder how long it would take to actually ship and what harm could come from shipping some core math functions now and then simply pulling them out when the namespacing stuff goes through.

@scottkellum
Copy link
Author

@scottkellum scottkellum commented Mar 25, 2015

The ** syntax Stylus and Ruby use is really nice. It’s a standard operator instead of a function. Not sure how that plays into namespace polluting but nobody said this needs to be a function.

@jakob-e
Copy link

@jakob-e jakob-e commented Mar 26, 2015

@scottkellum IMO you should keep the syntax as close to "basic front end" (HTML,CSS,JS) as possible – why pow($base, $exponent) is the better choice (and why ^ (XOR) should not be used either).

Arithmetic operators in JS:
 +  Addition
 -  Subtraction
 *  Multiplication
 /  Division
 %  Modulus
 ++ Increment    
 -- Decrement

PS. in relation to my suggested constant functions – if/when namespaces becomes available I picture them looking something like this math.$LN2 or @math.$LN2 or... but that's another story :)

@tabatkins
Copy link

@tabatkins tabatkins commented Sep 28, 2015

IMO you should keep the syntax as close to "basic front end" (HTML,CSS,JS) as possible – why pow($base, $exponent)

Note, tho, the currently-happening proposals to add an exponentiation operator to JS, spelled **. There's a bit of argument over whether it should require parens around the base or not (to prevent confusion when unary operators are employed, like -2**2 - is that 4 ((-2)**2) or -4 (-(2**2))?) but I'm fairly certain the operator will make it in.

@chriseppstein
Copy link

@chriseppstein chriseppstein commented Sep 28, 2015

Integer exponents on a number with units should always compute to (base ^ exponent)(unit^exponent).

Decimal exponents with units are strange to me. Not sure whether it should be an error or include a fractional unit (which is unlikely to cancel, therefore is rarely going to be printable as a CSS unit -- another kind of error that's harder to debug).

If you want the same unit you'll need to do something like: pow($somevalueinpixels / 1px, 3) * 1px

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 15, 2016

This has been open a few years. Have you had time to consider it and make a decision? 🍕

@corysimmons
Copy link

@corysimmons corysimmons commented Mar 15, 2016

3 years to come up with a namespace? 👏 💨

Actually, nevermind. I'll write lib in something else. Have nice day.

@tabatkins
Copy link

@tabatkins tabatkins commented Mar 16, 2016

@corysimmons No, 3 years to come up with a good, solid spec and implementation of namespacing and modules, while also handling all the other bugs and improvements that a popular living project like Sass generates.

Being rude can feel a little good in the moment, but it's never polite, and it's a major contributor to project-maintainer burnout. Next time you feel the need to leave a comment while annoyed, please consider waiting a while to cool down, and if you still feel like being a little rude, consider not posting at all.

@chris13524
Copy link

@chris13524 chris13524 commented Aug 27, 2017

So nothing on this yet? I just had a use for it.

@bichotll
Copy link

@bichotll bichotll commented Sep 20, 2017

Just wanted to say I was looking for it too 👍 I can wait.

...and seeing the comment on top, just wanted to thank the sass team! The world d not be the same without you! hah

@robclancy

This comment was marked as spam.

@tabatkins
Copy link

@tabatkins tabatkins commented Aug 8, 2019

CSS has at this point approved and specced a pow() function (along with some trig and other exponential functions).

Note that CSS does not allow pow() (or sqrt()) to take a value-with-unit, only plain numbers. There's an explanation in the draft for that.

@robclancy

This comment was marked as disruptive content.

@tabatkins
Copy link

@tabatkins tabatkins commented Aug 8, 2019

I'm not part of the Sass project, nor was I replying to you. I was just updating the thread.

You need to seriously reconsider how you interact with project maintainers. Negativity generally has the exact opposite effect of what you want; it certainly doesn't encourage people to work on the thing you're "asking" about.

@robclancy

This comment was marked as disruptive content.

@nex3
Copy link
Contributor

@nex3 nex3 commented Aug 8, 2019

@robclancy This is your one and only warning. Keep this up and you'll be blocked from this org.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet