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

Consider [LegacyStringClass] #547

Closed
travisleithead opened this issue Apr 12, 2018 · 13 comments
Closed

Consider [LegacyStringClass] #547

travisleithead opened this issue Apr 12, 2018 · 13 comments

Comments

@travisleithead
Copy link
Member

See: w3c/svgwg#175
@dstorey, @AmeliaBR

Folks working on SVG are trying to fix href and className in the SVG DOM to be more compatible with the HTML equivalent versions of those APIs. In HTML, these attributes get and set strings, in SVG they get SVGAnimatedString (and don't set), and SVGAnimatedString has baseVal (gets and sets string) and animVal gets a string only.

After a lot of thought, our "A" solution is to somehow make the SVGAnimatedString a type of actual string object for maximum compat, augmented with the baseVal and animVal attributes for backwards compatibility. This is the solution proposed in Issue w3c/svgwg#175.

How to actually do that? Following the pattern of Legacy... extended attributes, having SVGAnimatedString use a new [LegacyStringClass] seems like an option that might work, although there's a lot of assumptions we're making. We're hoping this issue and the smart folks working on WebIDL bindings can help work out if/how this could be achieved.

At it's surface, the interface would inherit from %StringPrototype%, but then we have a host of questions:

  • what does it mean for an IDL interface type to be a string type?
  • Is it possible to define all the string-like capabilities/semantics that this object would have to emulate?
  • How would this instance interact with the other built-in string operations? (Are the string operations in EcmaScript generic enough to work on "string-likes"?)
  • What is the mechanism for actually storing the string? How is a string type converted into this type when assigned to an attribute of this type?
    The list goes on.

If this is an insane idea, would love to know--it certainly seems like it will be complicated, but also pretty compatible if it does work.

@domenic
Copy link
Member

domenic commented Apr 12, 2018

My take is that this is probably not a great idea. String objects are generally confusing and a "mistake" in JavaScript (it would have been better to just have lowercase-s string primitive values). But, let's explore a bit...

Probably the best thing to do is figure out what programmer-facing experience you'd be able to achieve here. I can think of a few things:

  • Allow use in contexts that expect a string-like. This is doable without inheriting from String: just add a toString() method to SVGAnimatedString. (Maybe it already has one?) Every context on the web platform and the JS standard library will automatically work in this case.

  • Allow use of String.prototype methods, like substring/startsWith/etc. For example, a.href.substring(1). This would be what requires inheriting from String. But, how would these work? E.g. would substring() return a SVGAnimatedString, or a String, or a string? Would they operate on animVal or baseVal?

  • Not possible: have typeof a.href === "string" It will be "object" instead.

  • Not possible: have a.href === otherA.href even if their "real values" are equivalent. They will always be different objects, so will be !==. Similarly, you won't be able to ever make a.href === "some string literal" work. (Although you could make == work... but nobody uses that.)

Maybe there are more... will ask around/think harder.

My general takeaway is that you're most likely to land yourself in a weird uncanny valley by inheriting from String, and there's no real good solution here.

@annevk
Copy link
Member

annevk commented Apr 12, 2018

From https://svgwg.org/svg2-draft/types.html#InterfaceSVGAnimatedString it does not seem like it has toString(). Adding that to return the equivalent of baseVal would probably go a long way.

@ljharb
Copy link
Contributor

ljharb commented Apr 12, 2018

Being a proper subclass would enable String.prototype.toString.call and String.prototype.valueOf.call to not throw, at least, but otherwise adding toString seems like the path of least resistance.

@annevk
Copy link
Member

annevk commented Apr 12, 2018

(Note that we also researched string subclasses in the past for the CSSOM and it wasn't really workable. Though the angle there was to replace things that were strings.)

@tobie
Copy link
Collaborator

tobie commented Apr 12, 2018

@ljharb I'm curious why those string methods aren't generic. Web-breaking compat issues?

@ljharb
Copy link
Contributor

ljharb commented Apr 12, 2018

@tobie every builtin besides Error (until stacks arrive) has at least one available brand-checking method; I have no idea what the history is with String but i assume it was originally for legacy reasons.

@ljharb
Copy link
Contributor

ljharb commented Apr 12, 2018

@tobie as I think more about it, in order for those methods to be shared, the actual string data on a boxed primitive String would have to be per-instance, which necessitates an internal slot, which means the methods can’t be generic.

@tobie
Copy link
Collaborator

tobie commented Apr 12, 2018

@ljharb Right, but what prevents objects with a toString method to also have a [[StringData]] internal slot in that case?

@ljharb
Copy link
Contributor

ljharb commented Apr 12, 2018

@tobie nothing at all - svg String objects could easily have both, but the caveats mentioned #547 (comment) here would still apply.

@tobie
Copy link
Collaborator

tobie commented Apr 12, 2018

Agreed. But that would fix your concern expressed in #547 (comment).

@ljharb
Copy link
Contributor

ljharb commented Apr 12, 2018

Oh - to clarify, i don’t think it’s important to have those two methods work with svg strings - i was pointing out that that would be the only meaningful difference (since all the prototype methods could be shared or replicated)

@travisleithead
Copy link
Member Author

Appreciate the exploratory thoughts!

Allow use of String.prototype methods, like substring/startsWith/etc. For example, a.href.substring(1). This would be what requires inheriting from String. But, how would these work? E.g. would substring() return a SVGAnimatedString, or a String, or a string? Would they operate on animVal or baseVal?

This is indeed the tricky problem. Ideally, we'd want the SVGAnimatedString instance to have a [[StringData]] that the String.prototype methods would be able to operate on. We'd want all of the methods to return a (String or string) [not sure which]. The implementation of animVal and baseVal would simply read and write the [[StringData]].

However, it sounds like this path has been trod before, and there's not a great solution to subclass String objects (nor should we be encouraging this).

@travisleithead
Copy link
Member Author

[PutForwards] and stringifier it is. Thanks folks.

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

No branches or pull requests

5 participants