
Javascript: call functions without using parentheses - musikele
https://michelenasti.com/2018/09/19/Javascript-chiamare-funzioni-senza-usare-parentesi-(what!).html
======
spankalee
Calling a function without parens is probably the _least_ interesting part of
tagged template literals.

The key features of tagged template literals are:

* The tag function receives the string literals parts and values separately, before interpolation.

* The tag function can return anything, not just a string.

* The string literals are passed as a single argument (a TemplateObject) which is immutable and identical across multiple calls to the tag.

The last one is the kicker. It means that you can do something like this:

    
    
        const templateCache = new WeakMap();
        
        const html = (strings, ...values) => {
          let template = templateCache.get(strings);
          if (template === undefined) {
            template = makeTemplate(strings); // this might be expensive
            templateCache.set(strings, template);
          }
          return makeDOM(template, values);
        };
        
        const header = (title) => html`<h1>${title}</h1>`;
    

And now, no matter how many times you call header(), the work to create the
template is only done once because the strings is stable as a cache key.

Which is exactly what lit-html does to implement fast HTML templating :
[https://github.com/Polymer/lit-html](https://github.com/Polymer/lit-html)

~~~
globuous
Thanks for your comment, very interesting!

That being said, when you say that no-parenthesis are the least important
feature of templated strings, they seem to be mandatory for "deconstructing"
them via function arguments:

    
    
      const bar = "bar"
      f = (s, ...v) => console.log(s, v);
      f(`foo ${bar} baz`); // => foo bar baz ; []
      f`foo ${bar} baz`; // => ["foo ", " baz"] ; ["bar"]
    

So it's not so much that "you can call functions without parents in some
cases" or "they're not that nuts of a feature", rather than "if you want to
deconstruct templated strings, you must call your function without
parenthesis"

Which means that sometimes, there's just no other way around.

Cheers !

~~~
ehsankia
I think you're confusing what's happening here?

The first example is doing a normal string interpolation, and then passing the
result to a function. The latter is doing template literals, which is a whole
other feature. You're not really "running a function without parenthesis".

~~~
globuous
So you're not running a function when I write "f`some ${foo} lols`" ? What's f
then ? This is HN and I'm a self taught noob, so probabilistically I'm wrong
and you're right. But I'm having such a hard time believing it.

To me, it's still running the sequence of instructions defined by f in both
cases. Just that the arguments passed to f are different whether it's called
with parenthesis or not. And as far as I understand, that's the feature that
comes with string literals. But you're still calling f, and f is still a
function. It's defined as a function and executed as a function.

"If there is an expression preceding the template literal (tag here), this is
called a "tagged template". In that case, the tag expression (usually a
function) gets called with the processed template literal, which you can then
manipulate before outputting." \- [1]

Now when i open my console (FF) and I type:

    
    
      a = 12
      a`hello`
    

I get "TypeError: a is not a function". But if I do

    
    
      b = () => "yo"
      b`hello`
    

I get, as expected, "yo" and no TypeError.

Furthermore, I didn't know this feature, the article called it "functions
without using parenthesis" so i called it like that.

N.B. I'd like to know what the interpreter / JIT is doing now ;p

[1] [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates)

~~~
ehsankia
Eventually, f is called as a function, but in the syntax tree, it's not a
direct "function call". The obvious way to see that is, as you can see in your
example, "hello" isn't passed as an argument. Instead, there's an intermediate
form internally that does some magic, and calls the function with some other
parameters.

Maybe I was being a little pedantic, but yeah, f`test` and f(`test`) are two
very different operations under the hood.

------
eejdoowad
Sqorn author here.

Sqorn doesn't use tagged template literals to be cool. It uses them to make
writing SQL flexible, secure and intuitive.

You can write:

const boy = sq.from`person`.where`age < ${7} and gender = ${'male}`

to produce the query:

{ text: 'select * from person where age < $1 and gender = $2', args: [7,
'male'] }.

All methods have both template and non-template string forms you can choose
between. For example, the query above could also be written as:

sq.from('person').where({ maxAge: sq.l`age < ${7}`, gender: 'male' })

or even as:

sq`person``age < ${7} and gender = ${'male}`

or for those who like plain old SQL:

sq.l`select * from person where age < ${7} and gender = ${'male'}`

Read the tutorial at
[https://sqorn.org/docs/tutorial.html](https://sqorn.org/docs/tutorial.html)
to learn about the possibilities.

~~~
tolmasky
Sincere question: doesn't the use of template strings _increase_ the
possibility of injection where none would theoretically be possible in the
non-string version of the API? Not super familiar with the intended purpose of
sqorn, hence the real question, but I _think_ part of the goal of query
builders can be to very specifically constrain the possible generated output
statically.

So, for example in your example above, if I had tied the age parameter to some
input box, it is now theoretically up to the caller to sanitize age and make
sure the user doesn't type "10 || 1 = 1" or something. This as opposed to say,
doing .where(less_than(identifier("age"), input)), where you can absolutely
know that if input is not an int you can safely throw. I am basically making
the same injection question that's existed forever which is that if you deal
at the coarseness of string parsing, you lose the information of what is user
generated and what is programmer generated.

~~~
olooney
Putting a function in front of a backtick string _replaces_ normal string
introplation: instead of the default behavior, the function before the
backtick string gets passed the literal pieces of the template string and ${}
values explicitly and separately. Instead of returning an interpolated string,
the function can return whatever it wants. In sqorn's case, it returns an
Object with separate keys for sql and and values. When the time comes to
actually execute a query, sqorn passes these objects to database backends with
positional placeholders in the SQL ($1, $2, $3, etc.) and the values as
positional bound parameters. This is a safe way to prevent SQL injection.

~~~
tolmasky
Excellent, completely answers my question!

------
toomim
Another way to call a function without parentheses is with an ES5 getter (or
ES6 proxy):

    
    
        // The function we want to call
        function foo () { console.log('Hello!') }
    
        // ES5 getter:
        x = {}
        Object.defineProperty(x, 'foo', {get: foo})
    
        // Call it:
        x.foo               // Outputs 'Hello!'
    

What if we want to say "foo" instead of "x.foo"? Put a getter on window:

    
    
        Object.defineProperty(window, 'bar', {get: foo})
    
        // Call it:
        bar                 // Outputs "Hello!"
    

To pass arguments, use a setter instead:

    
    
        Object.defineProperty(window, 'hello', {set:
            function (x) {console.log('Hello '+x+'!')}
        })
    
        // Call it:
        hello = 'michael'   // Outputs "Hello michael!'
    

To support multiple arguments, pass an array or hash.

~~~
SwellJoe

        // Call it:
        hello = 'michael'   // Outputs "Hello michael!'
    

This makes me uncomfortable.

~~~
AzMoo_
With great power comes great responsibility. This is a situation in which the
old axiom, "don't write stupid code", comes into play.

~~~
shawn
But stupid code is the most fun.

------
DecoPerson
Interestingly, func`123 ${abc}` is not syntactic sugar for func(`123 ${123}`)
.

The latter interpolates the values into the template and passes the final
string to the function as a single argument.

The former acts as shown in the article, passing the string pieces as an array
and the value pieces as additional arguments. This allows SQORN to prevent SQL
injection while building queries. See first FAQ on
[https://sqorn.org/docs/faq.html](https://sqorn.org/docs/faq.html)

You can also do some interesting stuff with the special ".raw" property of the
string array passed. See here [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Template_literals#Raw_strings)

~~~
femto113
Worth noting also that there's nothing magical about the backtick being
adjacent to the function, you can have whitespace inbetween, e.g

    
    
         func   `123 ${abc}`
    

or even

    
    
         func
         `123 ${abc}`
    

Coupled with the vagueness around ; I expect this will make for some awesomely
obfuscated JavaScript in the coming years.

~~~
femto113
Even more nonsense possible since the tag function doesn't have to return a
string, it can return a function, meaning you could chain these, e.g.

    
    
        function tag2(string, ...keys) {
          console.log("tag2", string, ...keys);
          return function tag1(string, ...keys) {
            console.log("tag1", string, ...keys);
            return "tag1-return-value"
          }
        }
        console.log(tag2`input to tag2``input to tag1`);
    

yields

    
    
        tag2 [ 'input to tag2' ]
        tag1 [ 'input to tag1' ]
        tag1-return-value

------
burlesona
I also thought this looked crazy the first time I saw it.

I feel like ES6+ has jumped the shark in a bunch of ways. Adding new language
features can be nice, and shorthand syntax is sometimes convenient, but JS now
has a bunch of inconsistent rules about what you can and can’t do
syntactically.

These make for neato script tricks to impress your programmmer friends (“wait
you can do THAT?!) but I think it has mostly just made the language harder to
read.

But don’t worry we have build tools to fix it that will pick a single syntax
for your team! /s

~~~
phiresky
The template strings feature is not a just "shorthand syntax", it allows you
to do things that were not possible before (see [1])

[1] [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Template_literals#Raw_strings)

------
sondh
> Infact, apart from SQORN, I’ve never seen this syntax used elsewhere.

[https://www.styled-components.com](https://www.styled-components.com) maybe?

~~~
alephnan
Also,

[https://polymer.github.io/lit-html](https://polymer.github.io/lit-html)

[https://github.com/WebReflection/hyperHTML](https://github.com/WebReflection/hyperHTML)

------
bdcravens
Personally, I often use parentheses in languages like Ruby where avoiding them
is in vogue. Perhaps it's just a personal preference, but I feel it
communicates better (which is what source code is for)

~~~
pavel_lishin
I agree. Ambiguity kills software readability.

I'm currently learning Elixir at a new job, and I really, really dislike the
(what I think of as) the ruby-style where `return` statements and function
call parentheses are optional.

~~~
Shoue
I don't know Ruby or Elixir's way of doing this, but I assume it's not too
dissimilar to in Haskell and I'd argue there isn't much ambiguity -- the
spaces are enough to discern arguments once you get used to it, and if your
call gets too large maybe it's time to consider binding the arguments so it's
clearer what's being passed to the function anyway.

Same thing for implicit return statements, when they're implicit it just takes
getting used to the fact that the last statement in the block returns -- I've
never really had trouble reading code because of the lack of function call
parentheses or explicit return statements but I guess in a language where it's
optional it can be a bit more unexpected versus a language like Haskell where
this style is encouraged more strictly.

~~~
Retra
There's a good deal of ambiguity in Haskell, but people tend to resolve it
with operators like '$'. But I'd argue that it works very well in Haskell due
to the fact that whitespace as function application and automatic currying go
together well to make an elegant syntax. Lacking those features, it might be
better to stick to the standard parenthetical notation.

~~~
msla
> There's a good deal of ambiguity in Haskell

Obviously not.

------
kumarharsh
I'd like to point out that Relay also uses this template literal approach to
write graphql queries. Then there is styled-components which lets users write
css inside js and bind it to components using template literals.

It's not a "niche" usage, rather one of the raison d'etre of the feature. Even
the MDN docs point this out quite early in the text.

------
scriptnull
Thanks for mentioning about Sqorn. When I read about this feature a few weeks
back, I was thinking hard for a good use case of tagged template literals.
Now, I get it.

I agree with your closing statement completely.

> It’s a nice-to-know feature, good for impressing others, but my suggestion
> is to use this only if it’s the clearest way to express your concepts.

------
brockers
Can someone tell me what possible value this has?

~~~
naranha
It can be used for escaping values for example

var query = sql`select * from user where id=${id}`

Similar for html, preventing injection. You just need to implement the
corresponding functions.

For example [https://github.com/felixfbecker/node-sql-template-
strings](https://github.com/felixfbecker/node-sql-template-strings)

~~~
rbrcurtis
I don't see how this is better than

var query = sql(`select * from user where id=${id}`);

~~~
basil-rash
In this case the sql function can not escape the id. If you were to use a
tagged template, it could.

------
_xgw
This is pretty useful for saving 2 characters in codegolfing challenges.

For example:

> 'string'.split('').reverse().join('')

becomes

> 'string'.split``.reverse().join``

~~~
Roboprog
I was ready to hate on it too, until I learned (in the comments here, NOT the
article) that this is a special syntax for doing something like a C var-args
function - first a template parameter, then the variable list of values.

The function invoked does NOT simply receive the evaluated string, it gets the
template and can decide what to do with it, or not, including how to
encode/“escape” insertion values or other such issues.

------
mlthoughts2018
One of the worst syntactical aspects of Scala is that you can define methods
which cannot be called with invocation parentheses. Why anyone would ever want
this is beyond my understanding.

~~~
emodendroket
You're supposed to distinguish between functions with side effects and those
with none.

~~~
mlthoughts2018
What about methods that have arguments and no side-effects, like a special
getter that accesses a value in a Map of Maps? or functions that flush state
to I/O while doing other stuff and returning a value?

Why only make a special weird distinction for arg-less methods? And why enable
different ways of defining the method that can optionally require you to omit
parentheses rather than choose to do it only when you choose to write a
function that embodies that convention?

If you want a way to indicate side effects, make it a part of the type system
like in Haskell. Such a silly convention is unhelpful and I think fails even
at the intended goal because it confuses people thinking it’s not involving
the overhead of a function call.

~~~
emodendroket
Doesn't seem that different from the C# concept of properties, except with a
bit less language support. To me it doesn't seem that worth worrying about the
overhead of trivial function calls in the general case.

~~~
mlthoughts2018
But they often aren’t trivial, e.g. like breeze conversions to Scala data
structures that appear like simple attribute accesses and don’t indicate at
all that really they are complex function calls with important performance
considerations.

------
soylentgraham
Well, lack of parenthesis is just horrid (flashbacks to Visual Basic), but
kinda very happy to see one of the most useful things in php (and Delphi I
think?) finally arrive in a current language!

I've always thought I only wanted it in a high level language, but now... I
think I want it in c++ too... (just for debug of course, any pro knows user
facing strings stay outside for localisation)

------
iamrohitbanga
I feel where Ruby's optional parenthesis syntax really shines is in method
call chaining.

e.g.

    
    
        employees.flat_map(&:addresses).map(&:city).uniq.sort
        # in place of
        employees().flat_map(&:addresses).map(&:city).uniq().sort()

~~~
globuous
As a non-Ruby programmer, this sounds like it makes it non-obvious whether
you're calling a class' method or attribute. Do you end up relying on your
editor to help you out ?

~~~
techazard
It's actually nice that it does not matter if it's a function or attribute
that your calling in ruby. Check out the Uniform access principle
([https://en.wikipedia.org/wiki/Uniform_access_principle](https://en.wikipedia.org/wiki/Uniform_access_principle)).

When used correctly you can write IMHO really clean and concise OOP code where
(cascading) changes are easily made.

~~~
pavel_lishin
Where this kills me is ambiguous commas.

    
    
        something = [ alpha beta, gamma ]
    

I have no idea if I just invoked alpha(beta, gamma) and put the result into a
single-member array, or if I've got an array with two elements - alpha(beta)
and gamma.

~~~
dragonwriter
It's not _actually_ ambiguous; though it is a bit of language-specific syntax
to learn.

~~~
iamrohitbanga
Agreed. It is the "idiomatic" way of writing code in Ruby. I love Java but
writing lambda expressions in Java with deeply nested parenthesis makes the
code really ugly and less readable esp with chaining.

As far as I understand, Ruby style is writing the code in the most elegant way
to increase readability and (hopefully) reduce chances of bugs.

~~~
pavel_lishin
So what would you expect my example above do, at a glance?

Or is my example something that a good Ruby developer never write at all?

------
some1else
The pitfall being that this approach only works with string arguments. Having
some Ruby experience, I don't like any of the JavaScript DSLs using template
strings for function invocation so far (like styled-components and graphql),
and would rather just use macros:

\- Sweet.js: [https://jlongster.com/Stop-Writing-JavaScript-Compilers--
Mak...](https://jlongster.com/Stop-Writing-JavaScript-Compilers--Make-Macros-
Instead)

\- Babel-plugin-macros: [https://github.com/kentcdodds/babel-plugin-
macros](https://github.com/kentcdodds/babel-plugin-macros)

------
portal_narlish
This is a common paradigm in object-functional programming, as it further
emphasizes the duality of functions and the data they return. Scala allows one
to do this, however one could ostensibly pack a bunch of side effects into a
method and call it this way. Stylistically, these situations are supposed to
be differentiated. myObject.method() should be reserved for effectful
functions, and myObject.method for pure functions.

------
zackify
You could call functions by accessing methods like object.test if you simply
used es6 proxies. Same with extending the prototype, hardly a new concept

------
fersho311
I found out about this feature while using GraphQL. When going through
Apollo's docs I saw a bunch of gql`templateString`, which is used for defining
typeDefs. The first time I saw that, I was so confused. Personally, I think it
would be more clear if they just did gql(templateString)

~~~
burlesona
Using the parenthesis actually gives different behavior. That’s, I suppose,
why this syntax exists at all.

------
seattle_spring
This is almost as scary as all of the people that insist on not using
semicolons in JS.

~~~
Roboprog
The back ticks function as parens, effectively. The function receives multiple
arguments, NOT a single string. Think “sprintf”.

And semicolons are just noise :-)

------
carc1n0gen
I think another example of a library using template strings this way is
styled-components for react [https://www.styled-
components.com](https://www.styled-components.com)

------
galaxyLogic
As noted somewhere the template functions can return anything not just
strings. They can return functions.

Now my question: Isn't this the same as ability to define macros in other
high-level languages like Lisp for instance?

------
Kiro
Why doesn't console.log `foobar` work as imagined? It gives me an array.

~~~
fahrradflucht
Try adding interpolations to your example to make sense of this.

    
    
      console.log`foo${123}baz`
    

You get an array so that you later can interleaf the parts with the
interpolations you get as additional arguments.

------
oh-kumudo
Why?

This doesn't really have too much value other than making the code more
confusing.

------
raxxorrax
As someone with a german key layout, who is already used to pain when it comes
to parenthesis, this back-tick stuff is on a whole new level...

------
gmac
A nice use for this (tagged template literals) is bringing extended RegExps to
JS. [https://github.com/jawj/js-xre](https://github.com/jawj/js-xre)

------
jkoudys
stage 2 proposal for pipeline operator will also let you call functions
without parens.

    
    
        'hello world' |> console.log

------
jameslk
tl;dr it's just abusing ES6's template string functions

> const kid = sq.from`person`.where`age < 13`

Which just looks like a clever way to confuse people of what's going on. Try
explaining why this works to someone new to JavaScript. Not to mention the
maintenance nightmare this creates. Don't do this.

EDIT:

After others mentioned it, I understand now that for SQORN it is being used to
escape SQL parameters and this does seem valid.

However, the OP brings it up as a novelty to drop parenthesis from functions,
and for that I definitely think it's abuse without any value. This is not like
Ruby's optional parenthesis: it can only be used for template literals and it
makes your function implementation confusing.

~~~
AustinG08
It's a nice feature when used appropriately. Article says at the bottom in
bold: "It’s a nice-to-know feature, good for impressing others, but my
suggestion is to use this only if it’s the clearest way to express your
concepts."

~~~
jameslk
It's a nice feature, when used for template strings. Looking at the library,
it just looks awkward:

    
    
      sq.from`book`
        .return`distinct author`
        .where({ genre: 'Fantasy' })
        .where({ language: 'French' })
    

I can already hear the questions:

"Why do some functions require parenthesis and some don't?" "When do I need to
use parenthesis?"

It's just unnecessarily confusing.

~~~
lhorie
You're framing this as a question of syntax preference, but actually the whole
point of template tags is to cater to a very specific need: the ability to
sanitize an interpolated value.

In this specific example, let's say you have:

    
    
        sql.from`book`.return`distinct ${field}`
    

You don't want a sql injection to occur if somehow `field = 'author'; drop
table book; --` or similar.

With a plain function call, the library would have no way of knowing what to
sanitize.

    
    
        sql.from('book').return(`distinct ${field}`) // hello security hole
    

And without template tags, the API would arguably look more complex, and
require the user to discover/learn an ad-hoc interpolation DSL:

    
    
        sql.from('book').return('distinct ${field}', {field})
    

You can still target the template tag's raw API requirements without the
syntax (though you'd lose readability with multiple interpolations):

    
    
        sql.from('book').return(['distinct'], field)

------
mmis1000
you can call without parentheses already for those methods without parameters

window.toString = window.alert;

"" \+ window // alert popped

------
jaunkst
graphql-tags does this also

------
losvedir
parenthesEEEEEEEEEs!

------
ct520
Barf, no.

------
LiterallyDoge
This guy uses double quotes to make his example look more impressive and it
tilts me.

