Making sense out of Sass 3.5 first-class functions

Confused about the latest Sass Release Candidate blog post? So was I.

Sass 3.5.0-RC.1 marks the introduction of a new data-type: “first-class functions”. In the release candidate announcement, there is a four-paragraph long section about first-class functions that mentions a ton of details without showing any code. I didn’t really understand what it meant, so I decided to delve into it…

First class functions

The release candidate post states:

You can get a first-class function by passing its name to get-function($name)

This means that get-function($name) returns a first-class function.

What is a first-class function?

In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. – Wikipedia

That sounds nice. Good for you, functions! You just got a massive upgrade.

Then, the post mentions:

you can pass it (a first-class function) to call() where you used to pass the function name

This makes sense, but we still lack a few examples. I wanted to answer the question: “Where and why should we use get-function($name)?”

Let’s first see where we come from.

Calling a function in Sass < 3.5

Two options:

1. my-function($arguments)

This is the classic way to invoke a function. Nothing surprising here.

@function my-function() { @return ‘Hello, world.’; }
my-function(); // -> ‘Hello, world.’

2. or using call()

You may not be familiar with call(), and it’s normal. Most developers won’t ever need it, as it’s mostly useful to library developers.

We’re passing a function name to call(), which invokes said function.

@function my-function() { @return ‘Hello, world.’; }
call(‘my-function’)
// -> ‘Hello, world.’

Important: Sass 3.5 deprecates this option.

Any stylesheets that are currently passing around function names as strings should switch to passing first-class functions instead. To this end, calling call() with a string has been deprecated. It won’t actually break until 4.0, when it won’t be much use anyway, but we strongly encourage users to switch to get-function() immediately.

Examples:

Let’s see how to deal with option 2 (call()) in Sass 3.5.0 and up!

Calling a function in Sass 3.5 and up

As of Sass 3.5, you need to call functions with call() by passing it a first-class function, using get-function.

1. my-function($arguments)

This is still valid, don’t panic.

2. call(get-function(‘my-function’), $arguments)

You now have to pass call() a first-class function instead of a string:

3. call($my-function, $arguments)

That’s right, you can now assign a first-class function to a variable!

@​function my-function() { @​return ‘Great!’; }
$my-function: get-function(my-function); // New in Sass 3.5.0!
call($my-function); // -> Great!

Unfortunately, $my-function() and $foo(‘bar’) will not work.
It will fail to compile and you’ll get this error:

Error: get-function(“foo”) isn’t a valid CSS value.

At first glance, I think it’d be a good thing to be able to write $a(b) in Sass, but there might be implications I’m not considering! Let’s see where this goes in future versions.

Writing code compatible with all versions of Sass

Authors of libraries should upgrade to call(get-function()) (get it? it’s a library)

If you need to support multiple versions of Sass with your mixin, library, or framework, there are ways to write code that’s compatible with Sass 3.3, as well as newer and future versions.

1. Use function-exists

You can use function-exists($name) to determine if get-function is available (meaning you should pass a first-class function to call), and if not available, you fall back to the old call syntax (passing a string instead):

2. Use safe-get-function

I’ve put together a utility called safe-get-function that works across older and future versions of Sass, so you can start using get-function in your code today and be ready for Sass 3.5 and 4.0:

safe-get-function() is available today on npm:

npm install sass-safe-get-function

Download and contribute on GitHub:
https://github.com/kaelig/sass-safe-get-function

Wrapping up

My excitement when I read mentions of the new module system in Sass 4.0.0.

Nothing revolutionary in the upcoming 3.5 release, but I’m excited about these features in the context of Sass 4.0 and its new module system, where not everything is in the global scope (that’s a major change).

If your library or framework uses call(): now is a good time to start a new compatibility branch for Sass 3.5, and upgrade your code today using call(safe-get-function($name)) instead of call($name): https://github.com/kaelig/sass-safe-get-function.

If you’re not a Sass library developer: these changes probably don’t affect you, but hopefully this article made future Sass releases look less scary.

Want to play around with get-function? I’ve put together a playground repository: https://github.com/kaelig/sass-first-class-functions, have fun!

Resources

Acknowledgements

Thanks to Chris Eppstein for having a look and suggesting using function-exists to provide an upgrade path to library authors.