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

[Question] How did subexpressions come to use parentheses? #894

Closed
ErisDS opened this issue Oct 30, 2014 · 10 comments
Closed

[Question] How did subexpressions come to use parentheses? #894

ErisDS opened this issue Oct 30, 2014 · 10 comments
Milestone

Comments

@ErisDS
Copy link
Collaborator

ErisDS commented Oct 30, 2014

This is purely a question, I did a bit of digging but couldn't find any discussion on how the syntax came to be what it is - just the PR which added the feature.

Everything else in handlebars uses braces, there is no difference between a variable and a function, so I was wondering why such a different syntax was picked for subexpressions. Unlike the rest of the language, it is (in my opinion) pretty hard to guess what it means when you see {{myHelper (myOtherHelper)}} and in reverse, it's not easy to guess that if you want to pass one helper to another that's how you would do it.

In my experience from talking to people about their issues theming Ghost, most people guess / assume that you can do {{myHelper myOtherHelper}} - I assume there is a technical reason why it was not possible or desirable to make this work and also why {{myHelper {{myOtherHelper}}}} was not chosen?

@mmun
Copy link
Contributor

mmun commented Oct 30, 2014

The problem is that {{myHelper myOtherHelper myParam}} is ambiguous. In today's terms would it parsed as {{myHelper (myOtherHelper) myParam}} or {{myHelper (myOtherHelper myParam)}}? Both are needed.

Even if we chose a convention and tried to make it work, it's tricky because we don't know that myOtherHelper is actually a helper at compile time, and the presence of a helper would require different generated javascript in the compiled template. I think this could be made to work using the "known helpers" feature though.

Regarding braces, I think it was purely a stylistic choice, but there are deeper implications. The curlies don't just specify a subexpression - they also specify a boundary between handelbars content and non-handlebars content as well as how the handlebars content should be embedded into the surrounding content: e.g. escaped, unescaped, whitespace trimming, etc., whereas subexpressions are only concerned with computing values.

@mmun
Copy link
Contributor

mmun commented Oct 30, 2014

Another possibility is to introduce a low precedence operator like Haskell's $ so that

{{myHelper $ myOtherHelper myParam}}

will parse as {{myHelper (myOtherHelper myParam)}} but I don't think this will make things easier for beginners.

@kpdecker
Copy link
Collaborator

kpdecker commented Nov 2, 2014

@machty @wycats any feedback?

@wycats
Copy link
Collaborator

wycats commented Nov 2, 2014

@mmun is correct. Even {{myHelper myOtherHelper}} is unclear. Are you calling the other helper, or are you passing it as a function to myHelper. And {{helperA helperB param}} is even worse.

Nesting {{}} could possibly have worked, but {{format-date {{next-day date}}}} is pretty gnarly, and it gets worse with more nesting. Perhaps a single curly could have worked, although it would have made }}} as a closing curly visually ambiguous between a nested {} and the triple-curly escape syntax.

@ErisDS I'm quite interested to hear more about what people say when they are confused. Perhaps there is some tweak we can make that will make it easier for people to understand. Personally, this entire feature was very difficult for me; I knew it was crossing a complexity boundary, but the previous syntax made some common cases (like checking equality) unacceptably involved.

@ErisDS
Copy link
Collaborator Author

ErisDS commented Nov 2, 2014

I don't think I have sufficient evidence to prove there's a problem worth resolving, I was just reaching out to try to understand the decision making process.

I completely agree that the ambiguity problem precludes {{myHelper myOtherHelper}}, and I don't think a low precedence operator is a better solution - I can't even begin to imagine how I'd document that for non-developers! My gut feeling is that {{format-date {{next-day date}}}} is a nicer solution, because it doesn't create additional syntax to learn.

To answer @wycats's question about the confusion:

Essentially, the problem as I see it (and I think it's quite specific to our use-case) is that handlebars is mostly ambiguous: {{title}} could be a helper (function) or it could be a data accessor (variable) or it could in fact be both. This is a fantastic feature, because it means the person using it doesn't need to know either way - in fact they don't need to know anything about functions and variables, all they need to know about is the double-brace syntax, and what things they can put in-between.

Where this gets tricky is when you want to provide helpers which do something with that data, our main example being {{encode title}}. Now, all of a sudden, I need to know what title is in order to determine whether I need to do {{encode title}} or {{encode (title)}}.

The confusion comes from the not-knowing-in-the-first-place. In this case the user doesn't have any idea that there are even different possibilities for what {{title}} could be, let alone which thing it is, or how that changes its usage. Therefore the concept that a subexpression is even necessary is completely foreign. This makes it very difficult to document what the parenthesis are, why they are needed, and when they are needed.

Further to this, the parenthesis are specific, rather than ambiguous. They require a helper, otherwise an "object ### has no method call" error is thrown. I'd like to raise this issue separately as I believe the requirement that it be a helper is unnecessary and can be resolved?

Some background for anyone else:

We use handlebars via express-hbs along with a set of pre-determined helpers to provide an API for building Ghost themes. There is no option to add or customise your own helpers. Our core aim for themes is to make theming Ghost super easy and intuitive. Many of the people creating themes for Ghost come from a WP background and would classify themselves as designers first, developers second. There is also another main user group of hobbyists who (if we're lucky) have a working understanding of HTML. So far handlebars has stood up really well to both user groups - we get a lot of great feedback about how easy it is to create a Ghost theme.

@kpdecker
Copy link
Collaborator

kpdecker commented Nov 8, 2014

I can't say that I agree with the "additional syntax" comment. The complexity lies in having to learn the new feature. {{}} vs. () are an implementation detail of that feature.

Regrading the arguments to the helpers, if these are helpers that you are implementing, there is nothing that prevents you from evaluating the arguments in your helpers. This is actually what the if and with helpers do but it's not something we can do at the language level because we do not know wether the helper wants the function or the evaluated output from the function. Both are valid inputs to helpers.

Regarding the .call error, that sounds like a bug. Any chance you could put together a repo or test case?

@rwjblue
Copy link
Contributor

rwjblue commented Nov 25, 2014

My gut feeling is that {{format-date {{next-day date}}}} is a nicer solution, because it doesn't create additional syntax to learn.

I agree. Teaching a single way to invoke helpers is much less cognitive overhead.

@waynedpj
Copy link

My gut feeling is that {{format-date {{next-day date}}}} is a nicer solution, because it doesn't create additional syntax to learn.

👍

@kpdecker
Copy link
Collaborator

Closing this out as the syntax has been released for a number of versions now and without a compelling reason we can't arbitrarily change it (there are always two or more sides to every argument with things like this).

@ErisDS Can you open up a bug on the .call issue if you have a repo?

@kpdecker kpdecker added this to the 3.0 milestone Nov 26, 2014
@ErisDS
Copy link
Collaborator Author

ErisDS commented Nov 26, 2014

@kpdecker I'll get onto the bug asap. The reason I've not replied here in a little while is not that I've gone away and forgotten about this. Quite the opposite - I've been talking to developers who use handlebars to see if my sentiment is shared and trying to figure out how to make a compelling case for making the change from parenthesis to double brackets for subexpressions.

I 100% understand that this won't be an easy change to make, and that at the moment I'm just an outsider suggesting a really fundamental change with little-to-no basis. Still, I care a great deal about this and truly believe that the change will be worthwhile - I just need to figure out how to prove it :)

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

No branches or pull requests

6 participants