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

[css-values] String concatentation #542

Open
LeaVerou opened this issue Sep 28, 2016 · 15 comments

Comments

Projects
None yet
10 participants
@LeaVerou
Copy link
Contributor

commented Sep 28, 2016

As discussed with @tabatkins during TPAC last week.

Now with variables (custom properties), string concatenation is coming up in more and more use cases. Constructing URLs from variables for instance (see #541) is useless without concatenation.
Also, building SVG paths from variables.

Tab suggested a concat() function. I wonder if we can reuse the syntax from content which already allows for concatenation in a simple and elegant way, and special case the few cases where existing widely used property values accept <string>+ (e.g. quotes) if they are sufficiently few and concatenation isn't needed there. Sure, it's weird if concatenation doesn't work in a few places, but I think the usability benefits of doing concatenation in the same simple way that authors are already used to, are worth it. Otherwise, CSS will end up like LISP with all the parentheses (imagine things like concat(var(--text), calc(1% * var(--foo))), which will be pretty common).

Related specs:

@dauwhe dauwhe added the css-values-4 label Sep 28, 2016

@AmeliaBR

This comment has been minimized.

Copy link
Contributor

commented Jul 8, 2017

I'm intrigued by the idea of automatic concatenation of consecutive string tokens, but I'm worried that this might derail the general possibility of concatenation.

I personally don't think one extra layer of function notation will create an overwhelming number of parentheses. But maybe I've just been programming too long.

One thing I've mentioned elsewhere (and Lea seems to be assuming it, as well) is the idea that a concatenation function could do double-duty as a string coercion function, forcing any number or other non-string variables inside it into string version. This is very important for building SVG path data from variables. I'm worried that if you combine this with the default concatenation option you'd really make a mess of parsing.

So my vote is for a concat() or cat() or string() function. And sooner rather than later.

@LeaVerou

This comment has been minimized.

Copy link
Contributor Author

commented Apr 13, 2018

@tabatkins @fantasai Any thoughts? This is standing in the way of many cool CSS variable use cases, and once we agree on a syntax, not particularly hard to implement.
I got reminded of this because I was trying to use CSS variables in d: path(); yesterday, and quickly realized it was impossible :/.

@tabatkins

This comment has been minimized.

Copy link
Member

commented Apr 16, 2018

I'm strongly against the proposal to just make adjacent <string> values auto-concat; it clashes with existing grammars, restricts our ability to design reasonable grammars in the future, and this ability in 'content' isn't well-known anyway.

I'm supportive of concat() or string(). Having it auto-coerce things also seems fine to me, with the understanding that it'll use some well-defined notion of serialization, rather than necessarily preserving the exact input from the author.

(That is, string(1.0) might resolve to "1".)

@LeaVerou

This comment has been minimized.

Copy link
Contributor Author

commented Apr 23, 2018

@tabatkins Awesome, can we make it happen?

Regarding the name, I'd suggest text(). string() assumes knowledge of programming which doesn't necessarily apply to CSS authors, and concat() looks weird with only one argument. text() is also shorter.

@AmeliaBR

This comment has been minimized.

Copy link
Contributor

commented Apr 23, 2018

+1 to text() for being understandable and flexible.

Also +1 to Tab's suggestion that string serialization of numbers and lengths be independent of the formatting of the initial value. If there is demand in future, separate number formatting options could be considered, based on the number formatting options in counter().

@MeFoDy

This comment has been minimized.

Copy link

commented May 1, 2018

There is string() function here: https://www.w3.org/TR/css-gcpm-3/#using-named-strings.

Some printing tools have already implemented the behaviour from that working draft. I believe it's not really a good idea to have some new string() meaning. But it will be awesome to have a concatenating function named like text() or concat().

@css-meeting-bot

This comment has been minimized.

Copy link
Member

commented Feb 27, 2019

The CSS Working Group just discussed String Concatenation, and agreed to the following:

  • RESOLVED: work on astring-coercion-and-concatenation function
The full IRC log of that discussion <fantasai> Topic: String Concatenation
<astearns> github: https://github.com//issues/542
<fantasai> leaverou: There's a bunch of string value accepting proeprties in CSS, and can't use variables in there
<fantasai> leaverou: paths
<fantasai> leaverou: Lots of places where concatenation would be useful
<fantasai> leaverou: and don't have a way to do it
<fantasai> leaverou: Didn't recall any objections to the propsoal, just questions about what it's called
<fantasai> leaverou: I don't care, we just need a way to do it
<AmeliaBR> q+
<fantasai> chris: ppl using preprocessors take string concatenation for granted, it's simple there
<fantasai> chris: they're astounded when they find it's not available in raw CSS
<fantasai> leaverou: Primarily useful in URLs, but also useful in other places like paths
<fantasai> TabAtkins: I agree with the need for a function here, prefer concat() but fine with anything else
<chris> q?
<fantasai> leaverou: We've also had suggestions for a function that converts things to strings,
<xfq> ack AmeliaBR
<fantasai> leaverou: text() is generic enough to do both
<fantasai> string() sgtm
<fantasai> AmeliaBR: Problem with that is that for string coercion you often also want number formatting
<fantasai> AmeliaBR: so that might need to be a separate function
<fantasai> AmeliaBR: butwould need to be partof the system if you are going to make useful path dat from numeric variables
<fantasai> AmeliaBR: need to concatenate not just letters but numbers from variables
<fantasai> AmeliaBR: calc expressions
<dbaron> q+ to ask what the inputs to this function can be, and where it can be used
<fantasai> AmeliaBR: etc.
<fantasai> TabAtkins: What are the use cases for coercion? Debugging ovviousl, anything else?
<fantasai> leaverou: ...
<fantasai> Am Big in dataviz
<leaverou> s/.../generated content to display a variable value in the UI/
<leaverou> q+
<fantasai_> AmeliaBR: e.g. bar graphs, want to use value in drawing but also labelling
<fantasai_> AmeliaBR: don't want to duplicate content
<fantasai_> TabAtkins: I really don't want to get into string formatting
<fantasai_> TabAtkins: otherwise do see the value in do see value in displaying 50% on bar chart while 50% also used to size the bar chart
<fantasai_> AmeliaBR: So if we want to leave the generic number formatting issue for later, that's fine
<fantasai_> AmeliaBR: So long as we still have idea that basic concat function can take non-string values and simply print them out
<fantasai_> AmeliaBR: so you can use them for path data
<fantasai_> AmeliaBR: In path data you generally want to preserve maximum precision anyway
<fantasai_> leaverou: example ... interpolation
<fantasai_> leaverou: Don't want to define how concat() interpolates with each other
<xfq> ack db
<Zakim> dbaron, you wanted to ask what the inputs to this function can be, and where it can be used
<fantasai> dbaron: Reading the proposal wasn't clear to me what the inputs of this function is and what the output is in terms of types
<fantasai> dbaron: What CSS value types can be used in here?
<fantasai> TabAtkins: output tpe is tring
<fantasai> TabAtkins: input type is any thing, standard serialization of the token
<fantasai> dbaron: There will be a spec defining standard serialization of a token?
<leaverou> s/example ... interpolation/yes, that simplifies interpolation as well, if types of arguments were not coerced we'd need to define interpolation between two concat() calls
<fantasai> TabAtkins: Need that for variables anyway
<fantasai> TabAtkins: If it doesn't exist yet, some othe rspec is implicitly relying on it and it needs to be defined
<fantasai> astearns: Wrt used, it's anywhere with a string?
<fantasai> fremy: Exception for url?
<fantasai> TabAtkins: No, works in url()
<xfq> ack lea
<fantasai> TabAtkins: url() can take a string
<TabAtkins> s/take a string/take only a literal string, there's another issue for generic <string> input/
<fantasai> astearns: I'm hearing lots of nods on having this thing. Any implementer interest?
<fremy> (to clarify what tab said, url() can take a string but not a <string>)
<fantasai> astearns: From silence sounds like, yes this would be a good thing, no it's not a priority
<fantasai> emilio: Expectation is that you can do like sth(var(--whatev))?
<fantasai> emilio: Then how can you define it to be any token?
<fantasai> TabAtkins: var() is processed at a higher level than any value
<fantasai> fremy: If you want a string, you do text("string")
<TabAtkins> (It's specific as taking a <string> in the syntax, but in Syntax we handle url() in special ways that prevent it from taking string-producing functions.)
<fantasai> emilio: If it takes any token
<fantasai> fremy: If it's not a string, then you convert
<fantasai> TabAtkins: I think Emilio got it
<fantasai> astearns: OK, naming. What do we call the thing?
<fantasai> AmeliaBR: Lea suggested text(), but there's already a text() function in paged content
<fantasai> fantasai: How about string? was in Lea's original proposal
<fantasai> leaverou: sounds fine
<fantasai> chris: sounds fine
<bkardell_> lol
<fantasai> AmeliaBR: Sorry, confused things. It's the string() function that exists, text() does not
<fantasai> AmeliaBR: and already implemented
<chris> I care more that it exists, than what precisely it is called
<xfq> https://drafts.csswg.org/css-gcpm-3/#using-named-strings
<tantek> I for one an all for the cat() function, I bet it would poll well on Twitter 😺
<bkardell_> lol
<fantasai> astearns: Any objections to text()?
<chris> Lets go with text
<fantasai> dydz: Prefer concat(), but ...
<Rossen> combine()
<fantasai> AmeliaBR: Want names that are understandable by non-programmers in CSS
<fantasai> AmeliaBR: Also, we tend not to truncate identifiers in CSS
<chris> concat is not immediately obvious to non programmers either. both cat and concat are abbreviations
<fantasai> TabAtkins: We are not using cat(), tantek!
<tantek> 😿
<fantasai> bkardell_: I don't have a better suggestion, but text() is not very clear to me
<TabAtkins> text(50%)
<Rossen> +1 to bkardell_
<fantasai> bkardell_: There are so many ways that I coudl interpret "text"
<tantek> +1 to bkardell_
<fantasai> flatten() :P
<fantasai> chris: I think it's pretty clear
<fantasai> myles__: We should think about whether concatenation or coercion is more common use case
<TabAtkins> url(text("http://example.com", var(--foo)))
<florian> echo() ?
<tantek> printf()
<florian> printf()
<fantasai> AmeliaBR: text() is clear for coercion, maybe less clear for concatenation
<TabAtkins> No unixisms!
<TabAtkins> y'all weirdos!
<chris> and text(var(--foo)) with one param is clearer than concat(var(--foo))
<Rossen> stringify()
<Rossen> toString()
<TabAtkins> to-string()
<chris> DOTtoString
<dbaron> hopefully everybody has forgotten XPath by now?
<tantek> Time for a Twiter survey!
<fantasai> iank_: Spreadsheets use concatenate and concat
<fantasai> TabAtkins: It's terrible and hard to spell
<fantasai> TabAtkins: These are all great names, except for all the ones that are bad.
<chris> https://developer.mozilla.org/en-US/docs/Web/XPath/Functions/concat
<fantasai> TabAtkins: Let's table this and put together a non-binding Twitter poll
<fantasai> florian: Make sure you include an international audience
<fantasai> bkardell_: That works best if we all promote it so let us know
<fantasai> leaverou: Twitter doesn't have enough space for examples, and based on what examples you use can get different reactions
<fantasai> TabAtkins: I'll put together coercion example and concat example, and you can review them
<chris> https://stackoverflow.com/questions/9493732/difference-between-text-and-string
<fantasai> astearns: Sounds like we'll do this and decide the name later, would be interested in implementer interest
<fantasai> astearns: Any objections?
<fantasai> RESOLVED: work on astring-coercion-and-concatenation function
@kizu

This comment has been minimized.

Copy link

commented Feb 27, 2019

One thing I want to mention: what would be really nice if that future string concatenation could work with anything that accepts strings, especially, grid-template-areas, to allow generating named areas from other variables, for example.

Of course, this should work also by allowing converting idents into strings, so those could be reused both inside grid-template-areas and other grid properties.

And this also brings me to another kinda related topic: ident concatenation. Probably also related to converting anything into anything, and related to the attr()'s second argument. All of this is probably off-topic for this issue, but my point is: if we'd want to think about the name for string concatenation, we should remember that we could potentially have other functions in the future doing similar things, and we should come with a name that could work best in the wider picture.

@AmeliaBR

This comment has been minimized.

Copy link
Contributor

commented Feb 27, 2019

@kizu
I think the grid template use case would work with what we decided. If you use a non-string inside the function, it gets converted to a string based on its serialized value. The serialization of an ident is its character sequence. And it would definitely apply in any function that accepts a string data type.

Converting a string to a non-string (string to ident, string to parsed number or length) would be a separate issue. But I agree that adding a general parse function for that case is tied in with the unimplemented second parameter to attr.

@tabatkins

This comment has been minimized.

Copy link
Member

commented Feb 27, 2019

Yes, this function's type will be <string>; any place that accepts a <string> should accept it.

@BigBadaboom

This comment has been minimized.

Copy link

commented Feb 28, 2019

Playing devil's advocate for a moment... calc() already accepts seven different literal types. Why couldn't string be the eighth?

@SebastianZ

This comment has been minimized.

Copy link
Contributor

commented Feb 28, 2019

Playing devil's advocate for a moment... calc() already accepts seven different literal types. Why couldn't string be the eighth?

Because calc() is obviously for calculating something and deals with numeric values.

Sebastian

@AmeliaBR

This comment has been minimized.

Copy link
Contributor

commented Mar 1, 2019

@BigBadaboom And overloading calc() to do string concatenation would mean having to do calc("" + 50%) to get type coercion. And even if JS devs are used to that, it's still ugly.

@bradkemper

This comment has been minimized.

Copy link

commented Mar 2, 2019

string() already produces strings, and is understandable to css authors. I would rather not have string() produce a string one way, and text() produces a string another way. I would rather just extend string(). It seems doable. If the argument is an identifier that matches a string-set, then parse it as existing string(). Otherwise, coerce space-separated arguments into a string. Then allow this string to be used anywhere that strings are allowed.

I don’t buy the argument that CSS authors don’t know what “string” means. If that was the case, we shouldn’t have used it for GCPM. We have it there now, it exists, and it can be the single tool that authors reach for when they need a string.

@bradkemper

This comment has been minimized.

Copy link

commented Mar 2, 2019

It more CSS-y without the commas anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.