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

Update Glimmer Template Truthiness Semantics #861

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

bakerac4
Copy link

@bakerac4 bakerac4 commented Nov 16, 2022

Rendered

Provide a path for Glimmer templates to switch away from classic Handlebars truthiness to JavaScript’s truthiness. This will align our templating language with users' expectations and make teaching easier. It will also allow TypeScript features like type narrowing to work as users would expect it to with keywords like {{and}} or {{or}}.

@chriskrycho chriskrycho self-assigned this Nov 16, 2022
@chriskrycho chriskrycho added T-templates T-framework RFCs that impact the ember.js library T-TypeScript S-Proposed In the Proposed Stage labels Nov 16, 2022
@boris-petrov
Copy link

I'm confused, is this connected to this issue? Isn't updating these semantics going to break billions of apps?

@chriskrycho
Copy link
Contributor

  1. No, because assuming we do this, we are going to have a migration plan that allows the community to migrate incrementally.
  2. Billions of apps 🤣

Copy link
Member

@wagenet wagenet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great overall. Beyond my comments, I think there's a bit more minor editing work than can be done, mainly around consistent capitalization of JavaScript and TypeScript.

@chriskrycho
Copy link
Contributor

We talked a little bit about this at a high level at the Framework team meeting today (everyone is excited), and I'll review it early next week with the input from that!

Copy link
Contributor

@jelhan jelhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this RFC! I'm very much in favor of following native JavaScript more closely.

### Migration Plan
1. Ship comparison helpers `and`, `or`, `not` with existing equality and truthiness semantics (they currently match `if` and `unless` truthiness semantics)
2. Ship types which match that and document why they work they way they do. Acknowledge that this wont work for TS users in they way they would expect and why.
3. Ship ability to opt into new behavior for `and`, `or`, `not`, `if` and `unless` (Following JS truthiness semantics)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would that opt-in look like? Would be great if you could do more in detail for the migration story in general.

Takes at least two positional arguments. Raises an error if invoked with less than two arguments. It evaluates arguments left to right, returning the first one that is truthy (by javascript's definition of truthiness) or the right-most argument if all evaluate to falsy. This is equivalent to the {{or}} helper from ember-truth-helpers. Doing this would allow `{{or}}` to compile down to `||` and give us the correct type safety and narrowing that users would expect.

### {{not}}
Unary operator. Raises an error if invoked with more than one positional argument. If the given value evaluates to a truthy value (by javscript's definition of truthiness), the false is returned. If the given value evaluates to a falsy value (by javascript's definition of truthiness) then it returns true. This is equivalent to the {{not}} helper from ember-truth-helpers. Doing this would allow `{{not}}` to compile down to `!` and give us the correct type safety and narrowing that users would expect.
Copy link
Member

@bertdeblock bertdeblock Nov 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should {{not}} also error when invoked with no arguments?

Copy link
Author

@bakerac4 bakerac4 Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that this means anything, but according to the original RFC no? https://rfcs.emberjs.com/id/0562-add-logical-operators.

But that does bring about the question of what they were expecting to happen in that case? In my opinion, it would make sense to error there.

Edit: After playing around in a console I might have changed my mind. !undefined = true. And since we want to keep the semantics equal to Javascript - it might make sense to return true in this case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe still strange? I'm unsure. We definitely should support {{not undefined}} but I'm not sure about {{not}}.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would tend to not throw if invoked without arguments ({{(not)}}). But from typing perspective the argument should be required. And we might want to have a linting rule forbidding argumentless {{(not)}}.

I don't see much value in throwing. Implementation complexity should be the same. But we should use types and linting to push people towards {{false}} instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like @jelhan's solution here.

@wagenet wagenet removed the S-Proposed In the Proposed Stage label Jan 27, 2023
@wagenet wagenet added the S-Exploring In the Exploring RFC Stage label Jan 27, 2023
@wagenet
Copy link
Member

wagenet commented Aug 24, 2023

We should discuss what it takes for us to accept this at the next RFC Review.

@ef4
Copy link
Contributor

ef4 commented Sep 1, 2023

Two main bits of feedback:

  1. We need a more detailed migration plan. Does this use optional-features? Is the opt-in per-package or global? If it's global, how are people realistically supposed to upgrade without breaking their addons? What are addon authors supposed to do (they can't control when their consuming apps flip a global opt-in)? If it's per-package, how does that actually work at runtime (is there something visible in the actual compiled templates to say "this one uses the new boolean semantics"?).

  2. An important "Alternatives" topics is the idea of adding Javascript expression syntax to templates, something that we've discussed at length and people generally like as an idea, though no written design exists yet. Since that would also introduce new replacements for truth helpers, ones that would necessarily have javascript semantics, it seems like an area of overlap and it could make doing this RFC easier if we also did that one.

I have to say, I've been working in Glint quite a lot already and I've yet to hit a realistic example where this semantic gap actually came up. I would be curious to see people's examples. That doesn't mean I don't care about closing it, but I do think it's relevant to how we teach this and how we prioritize the migration.

@chriskrycho
Copy link
Contributor

The places it's likely to come up are exceptionally rare, but likely to be very annoying for people when they do happen, just insofar as they're a case where TS/Glint tells you they're safe and then you get a runtime error from it. Implicit in @ef4's comment is that Glint does let folks opt in (and our docs will better reflect that hopefully this week!).

That said, using a JS-expression-syntax would also solve this, and has the possibility a clear and straightforward opt-in at a template authoring level (e.g. a <template lang='something-good-here'> or some such along with an optional-feature to flip the default), and cleanly solves the problem from a Glint POV because there is no problem in that world: you just get TS semantics for free. Given the likely non-trivial work of migrating the truthiness semantics of existing Handlebars vs. switching to a JS expression syntax, my own personal preference would be extremely strongly toward the latter.

@wagenet
Copy link
Member

wagenet commented Sep 22, 2023

We should hash through this at the next feature design meting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-Exploring In the Exploring RFC Stage T-framework RFCs that impact the ember.js library T-templates T-TypeScript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants