-
Notifications
You must be signed in to change notification settings - Fork 191
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
support { toString(): string }
and { toHTML(): string }
as reactive outputs
#1578
Comments
What is the use case? |
|
one of the key things this allows is greater shareability and usability of boxed values (like translations). Today, there's no path for folks to use translations in module scope or in functions in module scope which leads to a lot of very odd patterns trying to map a mostly static concept to something app instance based. Beyond intl, at AuditBoard we've got a lot of use cases for boxed values around concepts like linkify: linkify is ostensibly an html value on a model coming from the API but really its an object with a bunch of knowledge of various things that can also be rendered as a link in a template context. EmberData itself has a lot of use for boxed values as well, making things like a rework of |
Also I'd note that I personally consider this change to be use-the-platform / feature-fill / fixing of the mental mode. It's generally presumed that if a value is rendered from a template, any tracked state that it accesses would result in a re-render when necessary. Glimmer today sort of accidentally memoizes a lot of things by only accessing these things from outside of the tracking context. |
Not obviously a good idea to me:
Specifically for the proposed change, – things would have to bottom out somewhere and you have to be able to expect a "scalar" value somewhere. Even in JavaScript, you generally can't e.g. return another another "string-like" from It's not that it's a hard feature to add, but I am not sure it's worth the cost/tradeoffs. Right now the code gets to make the assumption that when you get to the append/"value" position it bottoms out, and essentially this would force us to give that up and wrap everything in yet another tracking frame just in case, and I don't think it's worth it. Glint also isn't going to be happy with this. You can say If we have a method call syntax then imo it's not a big deal to have to call There are a lot of things we could do and a lot of things we can make more dynamic. We can have even an "value manager" to decide how to render any |
It doesn't actually, as per discussion in #1567, we need to specifically not call I don't think that's super relevant other than that, if your plan involves writing
There is no "existing" tracking frame here in this context, it will be a new tracking frame inserted just to make this work. Specifically when we are calling Currently we just pull the reference and check/coerce the resulting value as needed, but to make this work we would have to specifically add/wrap a tracking frame around all of these coercion points just in case. And to make this work consistently it would have to be the same in all of these sink positions (properties, attributes, etc) in ways, and in a few of these spots that can greatly complicate things on the off chance that it did end up changing. And, to re-iterate what I said in typed-ember/glint#708 (comment), we are not exactly talking about a missing capability here. You can definitely experiment and use boxed values and what not, we are just talking about whether we should always automatically/transparently (and reactively) unbox. I further agree it definitely wouldn't have be surprising if it did work that way, and if it's free to do I would probably say why not. But since we are talking about "always/transparently", it comes down the the tradeoff of the extra cost vs how common this really is. The alternative is that you add a helper like this in the app: function String(value: unknown): string {
let string = String(value);
assert("not like that!", string !== "[object Object]");
// and any other checks you may want
return string;
} But since this is a relatively rare occurrence, and that, as you said, a symbol is probably a better/more deliberate protocol/opt-in, you could also just do that: const VALUE = Symbol("BOXED VALUE");
export interface BoxedValue {
[VALUE](): string; // | undefined or whatever your needs are
}
export function unbox(boxed: BoxedValue): string {
return boxed[VALUE]();
} Then If you think about it, you could, hypothetically, AST transform all your But if that gives you a slight pause... that's roughly where I am coming from as well. |
You are seeing my point without seeing my point 🙈 We reduce complexity by having glimmer no longer do this coercion, instead the reference lookup becomes responsible for it. That lookup is also what starts a tracking frame, and so it doing this same check within itself fixes the autotracking problem pretty elegantly. We don't need a new tracking frame at all, and we simplify the branching of the code.
Given that nearly 100% of values in templates today are secretly boxed values, moving to an explicit unboxed API seems dangerously bad to DX. |
I don't see supporting either of these things as breaking, as today, you got
[object Object]
or similar when rendering "things with methods".What we need to make sure though,
toString()
, andtoHTML()
are reactive.Could replace:
glimmer-vm/packages/@glimmer/vm/lib/opcodes.ts
Lines 149 to 153 in f036320
The text was updated successfully, but these errors were encountered: