
On Tue, Aug 30, 2016 at 11:43:03PM +1000, Chris Angelico wrote:
On Tue, Aug 30, 2016 at 10:56 PM, Philipp A. <flying-sheep@web.de> wrote:
My issue is just that it’s as much of a string as a call of a (string returning) function/method or an expression concatenating strings:
''.join(things) # would you call this a string? '{!r}'.format(x) # or this? it’s basically the same as this “f-string”: f'{x!r}' 'start' + 'end' # or this? it’s a concatenation of two strings, just like f'start{ "end" }'
Yes, an f-string is really a form of expression, not a literal. But prior art has generally been to have similar constructs referred to as "interpolated strings" or similar terms:
*shrug* A misleading name is misleading no matter how many people use it. If <insert the name of a language you dislike here> started calling function calls: func(arg, x, y, z+1) "s-strings" for "source code strings", because you write them as source code, and changed the syntax to func"arg, x, y, z+1" we'd all recognise what a mistake it is to call this a string, string delimiters or not. The *result* of calling it may be a string, but the expression itself is a kind of function call. [nasty thought] Why don't we allow func"*args" as syntactic sugar for str(func(*args))? [/remove tongue from cheek]
Plenty of languages have some such feature, and it's usually considered a type of string.
The result is a type of string. The expression is not.
Notice the close parallels between actual string literals used as format strings ("I have %d apples" % apples) and f-strings (f"I have {apples} apples"),
That's a misleading comparison. The *template string* is "I have %d apples" and that is just a string. The *format operator* is % and the formatting operation or expression is the entire expression. Since f-strings can contain arbitrary expressions, the analogy is not with the template string, but a function (method or operator) call: f"I have {fruit - bananas - oranges} apples" is not equivalent to "I have {} apples", but to "I have {} apples".format(fruit - bananas - oranges) which is clearly a method call that merely returns a string, not a string itself. Consequently, there's no way to delay evaluation of such an f-string, any more than you can delay evaluation of the expression[1]: func(fruit, 2*bananas, 3/oranges) You can't generate a template, and pass it to different environments to be formatted. If you need to evaluate f"I have {apples} apples" in six different contexts, you have to repeat yourself: it is equivalent to a function call, complete with implicit arguments, not a function object, and certainly not equivalent to a template string.
and how this same parallel can be seen in many other languages. Yes, it may be a join expression to the compiler, but it's a string to the programmer.
Only if the programmer is fooled by the mere use of string delimiters. It really isn't a string. It is executable code that returns a string. It is basically a distant cousin to eval(), in disguise. I really wish we had a better name for these things than f-strings :-( [1] Tricks with eval() excluded. -- Steve