220 20521 <CAB+4KHKU-rA6Os77FLT4Vm2CrPKzMiMpACk2LrGq5r0Khkp9Bg@mail.gmail.com> article
Path: news.gmane.org!not-for-mail
From: Andrew Tomazos <andrewtomazos@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Rough Draft Proposal of Interpolated String Literals
Date: Sun, 20 Sep 2015 15:01:26 +0200
Lines: 605
Approved: news@gmane.org
Message-ID: <CAB+4KHKU-rA6Os77FLT4Vm2CrPKzMiMpACk2LrGq5r0Khkp9Bg@mail.gmail.com>
References: <CAB+4KHKxwEPXSFScU-FjeUL=yQFZWGfm6uk5fbh1+9bfScL_2Q@mail.gmail.com>
	<55FC8A6B.1070100@gmail.com>
	<650f78b0-289e-4880-9c03-8615b25360ec@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: plane.gmane.org
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary=089e0103009cd7c95505202d5c1d
X-Trace: ger.gmane.org 1442754091 15518 80.91.229.3 (20 Sep 2015 13:01:31 GMT)
X-Complaints-To: usenet@ger.gmane.org
NNTP-Posting-Date: Sun, 20 Sep 2015 13:01:31 +0000 (UTC)
To: "std-proposals@isocpp.org" <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBD5KHQXXWYPRBJ647KXQKGQE5HMIHTA@isocpp.org Sun Sep 20 15:01:30 2015
Return-path: <std-proposals+bncBD5KHQXXWYPRBJ647KXQKGQE5HMIHTA@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-wi0-f197.google.com ([209.85.212.197])
	by plane.gmane.org with esmtp (Exim 4.69)
	(envelope-from <std-proposals+bncBD5KHQXXWYPRBJ647KXQKGQE5HMIHTA@isocpp.org>)
	id 1ZdeFF-0002zu-0Z
	for gclcip-std-proposals@m.gmane.org; Sun, 20 Sep 2015 15:01:29 +0200
Original-Received: by wisv5 with SMTP id v5sf23173785wis.0
        for <gclcip-std-proposals@m.gmane.org>; Sun, 20 Sep 2015 06:01:28 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=x-gm-message-state:mime-version:in-reply-to:references:date
         :message-id:subject:from:to:content-type:x-original-sender
         :x-original-authentication-results:reply-to:precedence:mailing-list
         :list-id:x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=0/bXbRxMlouxVUarFI46inHbMK9469QVn8iqYL+zsv8=;
        b=Ady+HrorHGLzsMCSAwMtYTZD3nnWenBVC8UaACLifiJFtZrio9zY35gfWaZtWw9ms1
         giOAZKMcxCroIK+yvJm4YcdQWXEwcLBvrahsnNM9OT0YaegA8oxlrLt9BG0zVwh31PAO
         TiOnEuQ1b2gqzpN6raKEZLiUL5JrRQ/auuOg0znCrS8X43zeojcKIUw38gyVrCqoYmSe
         V8taWfwMwQ4R1dyBtKTDmOq/OOV/yNs1adNwNX4LD61CvMC8FHiP8qzdsLb2i9ikVRWT
         /UmiNZZzNa0WvwSyg+XxCTGxkkaay+CcmBnF6LOC+8Iy4eQbTLlcAcolC1+RAg/GEdZX
         FtNg==
X-Gm-Message-State: ALoCoQm5lyQ6zZK4d0iPqCdFU9wMxfb7OW/ZWju59qL650gl0wkJtlaEf4ziY0+U6PwlBMWSlXWG
X-Received: by 10.194.93.198 with SMTP id cw6mr2417622wjb.3.1442754088287;
        Sun, 20 Sep 2015 06:01:28 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.180.75.140 with SMTP id c12ls497882wiw.7.gmail; Sun, 20 Sep
 2015 06:01:27 -0700 (PDT)
X-Received: by 10.180.219.101 with SMTP id pn5mr7664028wic.89.1442754087052;
        Sun, 20 Sep 2015 06:01:27 -0700 (PDT)
Original-Received: from mail-wi0-x230.google.com (mail-wi0-x230.google.com. [2a00:1450:400c:c05::230])
        by mx.google.com with ESMTPS id hq5si24520500wjb.134.2015.09.20.06.01.27
        for <std-proposals@isocpp.org>
        (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
        Sun, 20 Sep 2015 06:01:27 -0700 (PDT)
Received-SPF: pass (google.com: domain of andrewtomazos@gmail.com designates 2a00:1450:400c:c05::230 as permitted sender) client-ip=2a00:1450:400c:c05::230;
Original-Received: by wicgb1 with SMTP id gb1so82647883wic.1
        for <std-proposals@isocpp.org>; Sun, 20 Sep 2015 06:01:27 -0700 (PDT)
X-Received: by 10.194.103.103 with SMTP id fv7mr20502127wjb.152.1442754086814;
 Sun, 20 Sep 2015 06:01:26 -0700 (PDT)
Original-Received: by 10.28.73.137 with HTTP; Sun, 20 Sep 2015 06:01:26 -0700 (PDT)
In-Reply-To: <650f78b0-289e-4880-9c03-8615b25360ec@isocpp.org>
X-Original-Sender: andrewtomazos@gmail.com
X-Original-Authentication-Results: mx.google.com;       spf=pass (google.com:
 domain of andrewtomazos@gmail.com designates 2a00:1450:400c:c05::230 as
 permitted sender) smtp.mailfrom=andrewtomazos@gmail.com;       dkim=pass
 header.i=@gmail.com;       dmarc=pass (p=NONE dis=NONE) header.from=gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Spam-Checked-In-Group: std-proposals@isocpp.org
X-Google-Group-Id: 399137483710
List-Post: <http://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <http://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <http://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:20521
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/20521>

--089e0103009cd7c95505202d5c1d
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Sat, Sep 19, 2015 at 12:33 PM, Bengt Gustafsson <
bengt.gustafsson@beamways.com> wrote:

> - Do we really need to be able to specify the introducer character. Can't
> % be fixed (with the usual %% escape possibility).
>

I considered that, but no matter what introducer you pick, there are always
cases where the introducer is prevalent in the target string.  This occurs
in natural language, but is especially the case of code generation, where
you are generating strings for later compilation in C++ or some other
programming language.  Having the introducer be defined at the start also
makes it easier to read, as you are reminded what the special token is
(just like the compiler is).

Compare:

   F"The result of %x %% %y is not zero (it is %(x%y))."

with

   F"$ The result of $x % $y is not zero (it is $[x%y])."

Similar problematic examples can be found with any set predefined
introducer or set predefined brackets.

- Wouldn't it be more logical if this resulted in an expanded pack, i.e. a
> number of comma separated parts.
>

format(std::cout, F"The number of %goods is %count");
>

No, I think:

  std::cout F"% The number of %goods is %count";

is better.

But I am considering changing the definition of an interpolated string to
be a function call expression of return type std::interpolated_string.

This would mean we would have to write:

  std::cout << F"% The number of %goods is %count";

(which some have requested anyway).

But it also means we could also write:

  std::string s =3D F"% The number of %goods is %count";

or use it anywhere you can use a string normally.

std::interpolated_string would contain:
1. a reference to the constant expression format string and positions of
embedded expressions (which are known at compile time)
2. references to the values of the evaluated embedded expressions for the
current execution. (calculated at run-time usually, but it should be
constexpr-compatible)

This means the operator<<(ostream&, interpolated_string) could be defined
to stream out the substrings and subexpressions just like (and just as
efficiently) as if you had written << for each.

For the conversion from std::interpolated_string to std::string, it could
use std::ostringstream internally or some more efficient method.

So consumers of std::interpolated_strings could use operator<<(ostream&,
std::interpolated_string), or use the conversion from
std::interpolated_string to std::string implicitly (by just using
std::string or std::string_view), or they could overload on
std::interpolated_string.

Users could also overload on std::interpolated_string to implement a
translation mechanism, as they would have access to both the original
source code text of the expressions as well as their evaluated values.

std::interpolated_string would actually be a class template parametric on
the types of the embedded expressions, but that's an implementation detail.


> which calls a:
>
> template<typename... Ps> void format(ostream&, Ps&&...);
>
> Arbitrarily reusing << is a little bit to much of a hack for my taste.
> Expanding as a pack to be picked up by a variadic template seems more lik=
e
> modern C++. The upcoming ... << ... type pack expansions
> of C++17 would make the implementation of format a breeze.
>
> Even with a << expansion I would prefer not to introduce an prefix one at
> the left, it seems more logical to write it out explicitly.
>
> - Translation is an important issue.
>
> There are utilities which scan the source code to find typically
> _("string") literals which get translated. This does not seem to play wel=
l
> with
> this suggestion. Translation is probably the most important reason for
> placing the inserts after the string literal in printf and similar, and
> this makes inline systems like shifting out on cout
> much harder to translate, and this suggested system even worse, as the
> parts of the literal can't be "addressed" at runtime so there is no chanc=
e
> of replacing the string with a translation.
>
> Translation is also a main driver behind prefering named inserts, as
> different languages tend to want to reorder inserted words to get a
> grammatically correct sentence.
>
> This said there are of course uses when translation is not an issue, but
> I'm a bit worried that making untranslatable strings so much easier to us=
e
> than translatable strings will make American programmers (who are as lazy
> as all programmers and create many of the most used softwares) convenient=
ly
> forget about the needs for translation.
>
> Of course it is still possible to make a preprocessor which actually
> mangles the source code inserting the foreign string, but we want to move
> away from those ideas towards being able to change language at runtime.
>
>
> Den l=C3=B6rdag 19 september 2015 kl. 00:04:23 UTC+2 skrev Miro Knejp:
>
>> Nice, I wanted this so many times already.
>>
>> But there are a few points I find a bit strange.
>>
>> (1) I don't think operator<< is the right choice. With your proposal it
>> means I cannot do the very basic thing that works in every language with
>> string interpolation:
>> std::string s =3D F"% Hello %i World!";
>> auto s =3D F"% Hello %i World!"; // What is auto?
>> Any proposal that cannot get the above two lines to "just work" with
>> standard types is simply not good enough in my oppinion.
>>
>> I believe to make this work properly one needs some other infrastructure
>> to exist first. There has to be a way to pass the expression to be
>> formatted to some function that knows how to format it? Last time I used
>> string interpolation was in Scala, where the literal prefix is actually =
the
>> name of a function to call with the transformed string. I don't know
>> whether we can ever introduce user defined string prefixes, but who know=
s.
>> However, I think for now, a more flexible way is to combine both prefix =
and
>> suffix. Let me try to explain with an example using your syntax where
>> applicable:
>>
>> auto s =3D F"% Hello %i World: %{x =3D=3D 1 ? "a" : "b"}!"_my_string;
>>
>> This is translated to something like:
>> auto&& __context =3D operator""_my_string();
>> __context("Hello ");
>> __context(i);
>> __context(" World: ");
>> __context(x =3D=3D 1 ? "a" : "b"); // Note the correct handling of liter=
als
>> inside %{ }
>> __context("!");
>> auto s =3D move(__context).get();d
>>
>> Whatever x this UDL returns must make the expression x(expr) well-formed
>> for every expr that is an embedded expression of the string literal, or =
an
>> actual string literal. Unfortunately this requires that a string literal
>> with *only* the introducing prefix is ill-formed, unless we make the
>> exception that a lacking suffix uses a standard-library context that
>> produces a std::string (whether this is a good idea is debatable, but it
>> sure as hell would be friggin' convenient). Assuming no exceptions the
>> get() method is invoked exactly once and therefore can use this knowledg=
e
>> to move the result out of the object. The move() helps to prefer an
>> rvalue-qualified overload if one exists.
>>
>> The UDL is declared as usual but takes no parameters:
>>
>> MyStringBuilder operator""_my_string();
>>
>> This suggests that the context cannot take constructor parameter, which
>> may be a severe limitation. If constructor arguments are desirable then =
it
>> would certainly need a syntax that distinguishes this UDL from others (o=
r
>> find a solution other than UDLs). An interpolated string that is used fo=
r a
>> purpose other than being stored in some location (like performing output=
)
>> it is more efficient to perform the output directly, which I guess is th=
e
>> motivation of using operator<<. A context that can take parameters could
>> make this possible, for example using llvm::raw_ostream (a faster
>> alternative to std::ostream):
>>
>> using namespace llvm;
>> raw_ostream out;
>> F"% Hello %i World: %{x =3D=3D 1 ? "a" : "b"}!"_raw_ostream{out};
>>
>> Using a wrapper around raw_ostream that uses operator() instead of
>> operator<< can directly insert into the stream with zero overhead compar=
ed
>> to a handwritten sequence of statements (same applies for std::ostream).
>> What is weird about this syntax, though, is the placement of the "thing"
>> that does the actual work at the end of the expression instead of the fr=
ont
>> as it were in a function call. Your approach with the receiving object a=
t
>> the front makes it at least *look* better. Maybe these can somehow be
>> combined.
>>
>> Regardless of whether my approach here works or not, I think a solution
>> that is not directly coupled to a certain operator (except the call
>> operator) is less restricted and far more flexible. Function objects are
>> way more common than insertion operators and maybe we can slow down the
>> spreading abuse of operator<< . I know of some classes that could be an
>> immediate drop-in and would "just work" with minimal adjustments. If the
>> standard-provided string context uses ADL-based lookup to (for example)
>> to_string(x), or to_string(context, x), you have a convenient customizat=
ion
>> point to support the default string interpolation.
>>
>> (2) Even if you stick to operator<< I find it *very* disturbing that
>> there is no << between cout and the literal.
>>
>> cout F"% ..."; // Where's the operator? No call parens? Am I blind? Is
>> the sky falling?
>> cout << F"% ..."; // Ah, there it is!
>>
>> It also means that with your approach I couldn't pass the result of the
>> interpolated literal as function parameter.
>>
>> foo(F"% ...") // ill-formed: foo(<< "...")
>>
>> (Which would be also ill-formed if the compiler can't find a matching
>> operator<<, but that's a different issue.)
>>
>> It has to be as convenient and flexible as possible for the end-user.
>>
>> (3) I think it's very strange to have the escaping character be part of
>> the string literal. To me it lacks a clear separation between the actual
>> literal content and the introducer. Look at raw literals:
>> R"delimiter(...)delimiter" where there is a clearly visible distinction
>> between "content" and "non-content". Not sure how to do this properly,
>> especially regarding the next point:
>>
>> (4) How does this combine with the other literal prefixes, like R?
>>
>> (5) There are actually two proposals in there: string interpolation and
>> multiline literals. Those are completely orthogonal and you don't need t=
he
>> one to implement the other. You'd be better off making these two separat=
e
>> (independent) proposals.
>>
>> Am 18.09.2015 um 22:21 schrieb Andrew Tomazos:
>>
>> Please find attached a very very rough draft of a proposal entitled
>> "Interpolated String Literals".
>>
>> Mainly after encouragement or discouragement, and any high-level thought=
s
>> you might have about it.
>>
>> --
>>
>> ---
>> You received this message because you are subscribed to the Google Group=
s
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send a=
n
>> email to std-proposal...@isocpp.org.
>> To post to this group, send email to std-pr...@isocpp.org.
>> Visit this group at
>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>>
>>
>> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

--089e0103009cd7c95505202d5c1d
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On S=
at, Sep 19, 2015 at 12:33 PM, Bengt Gustafsson <span dir=3D"ltr">&lt;<a hre=
f=3D"mailto:bengt.gustafsson@beamways.com" target=3D"_blank">bengt.gustafss=
on@beamways.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" =
style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:r=
gb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr">=
<div>- Do we really need to be able to specify the introducer character. Ca=
n&#39;t % be fixed (with the usual %% escape possibility).</div></div></blo=
ckquote><div><br></div><div>I considered that, but no matter what introduce=
r you pick, there are always cases where the introducer is prevalent in the=
 target string.=C2=A0 This occurs in natural language, but is especially th=
e case of code generation, where you are generating strings for later compi=
lation in C++ or some other programming language.=C2=A0 Having the introduc=
er be defined at the start also makes it easier to read, as you are reminde=
d what the special token is (just like the compiler is).</div><div><br></di=
v><div>Compare:</div><div><br></div><div>=C2=A0 =C2=A0F&quot;The result of =
%x %% %y is not zero (it is %(x%y)).&quot;</div><div><br></div><div>with</d=
iv><div><br></div><div>=C2=A0 =C2=A0F&quot;$ The result of $x % $y is not z=
ero (it is $[x%y]).&quot;</div><div><br></div><div>Similar problematic exam=
ples can be found with any set predefined introducer or set predefined brac=
kets.</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204)=
;border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div></div><div=
>- Wouldn&#39;t it be more logical if this resulted in an expanded pack, i.=
e. a number of comma separated parts.</div></div></blockquote><div><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid=
;padding-left:1ex"><div dir=3D"ltr"><div>format(std::cout, F&quot;The numbe=
r of %goods is %count&quot;);</div></div></blockquote><div><br></div><div>N=
o, I think:</div><div><br></div><div>=C2=A0 std::cout F&quot;% The number o=
f %goods is %count&quot;;</div><div><br></div><div>is better.</div><div><br=
></div><div>But I am considering changing the definition of an interpolated=
 string to be a function call expression of return type std::interpolated_s=
tring.<br></div><div><br></div><div>This would mean we would have to write:=
</div><div><br></div><div><div>=C2=A0 std::cout &lt;&lt; F&quot;% The numbe=
r of %goods is %count&quot;;</div></div><div><br></div><div>(which some hav=
e requested anyway).</div><div><br></div><div>But it also means we could al=
so write:</div><div><br></div><div>=C2=A0 std::string s =3D F&quot;% The nu=
mber of %goods is %count&quot;;</div><div><br></div><div>or use it anywhere=
 you can use a string normally.</div><div><br></div><div>std::interpolated_=
string would contain:<br></div><div>1. a reference to the constant expressi=
on format string and positions of embedded expressions (which are known at =
compile time)</div><div>2. references to the values of the evaluated embedd=
ed expressions for the current execution. (calculated at run-time usually, =
but it should be constexpr-compatible)</div><div><br></div><div>This means =
the operator&lt;&lt;(ostream&amp;, interpolated_string) could be defined to=
 stream out the substrings and subexpressions just like (and just as effici=
ently) as if you had written &lt;&lt; for each.</div><div><br></div><div>Fo=
r the conversion from std::interpolated_string to std::string, it could use=
 std::ostringstream internally or some more efficient method.</div><div><br=
></div><div>So consumers of std::interpolated_strings could use operator&lt=
;&lt;(ostream&amp;, std::interpolated_string), or use the conversion from s=
td::interpolated_string to std::string implicitly (by just using std::strin=
g or std::string_view), or they could overload on std::interpolated_string.=
</div><div><br></div><div>Users could also overload on std::interpolated_st=
ring to implement a translation mechanism, as they would have access to bot=
h the original source code text of the expressions as well as their evaluat=
ed values.</div><div><br></div><div>std::interpolated_string would actually=
 be a class template parametric on the types of the embedded expressions, b=
ut that&#39;s an implementation detail.</div><div><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;=
border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex=
"><div dir=3D"ltr"><div><br></div><div>which calls a:</div><div><br></div><=
div>template&lt;typename... Ps&gt; void format(ostream&amp;, Ps&amp;&amp;..=
..);</div><div><br></div><div>Arbitrarily reusing &lt;&lt; is a little bit t=
o much of a hack for my taste. Expanding as a pack to be picked up by a var=
iadic template seems more like modern C++. The upcoming ... &lt;&lt; ... ty=
pe pack expansions</div><div>of C++17 would make the implementation of form=
at a breeze.</div><div><br></div><div>Even with a &lt;&lt; expansion I woul=
d prefer not to introduce an prefix one at the left, it seems more logical =
to write it out explicitly.</div><div><br></div><div>- Translation is an im=
portant issue.</div><div><br></div><div>There are utilities which scan the =
source code to find typically _(&quot;string&quot;) literals which get tran=
slated. This does not seem to play well with</div><div>this suggestion. Tra=
nslation is probably the most important reason for placing the inserts afte=
r the string literal in printf and similar, and this makes inline systems l=
ike shifting out on cout</div><div>much harder to translate, and this sugge=
sted system even worse, as the parts of the literal can&#39;t be &quot;addr=
essed&quot; at runtime so there is no chance of replacing the string with a=
 translation.</div><div><br></div><div>Translation is also a main driver be=
hind prefering named inserts, as different languages tend to want to reorde=
r inserted words to get a grammatically correct sentence.</div><div><br></d=
iv><div>This said there are of course uses when translation is not an issue=
, but I&#39;m a bit worried that making untranslatable strings so much easi=
er to use than translatable strings will make American programmers (who are=
 as lazy as all programmers and create many of the most used softwares) con=
veniently forget about the needs for translation.</div><div><br></div><div>=
Of course it is still possible to make a preprocessor which actually mangle=
s the source code inserting the foreign string, but we want to move away fr=
om those ideas towards being able to change language at runtime.</div><div>=
<div><div class=3D"h5"><br><br>Den l=C3=B6rdag 19 september 2015 kl. 00:04:=
23 UTC+2 skrev Miro Knejp:</div></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(=
204,204,204);border-left-style:solid;padding-left:1ex">
 =20
   =20
 =20
  <div bgcolor=3D"#FFFFFF" text=3D"#000000"><div><div class=3D"h5">
    Nice, I wanted this so many times already.<br>
    <br>
    But there are a few points I find a bit strange.<br>
    <br>
    (1) I don&#39;t think operator&lt;&lt; is the right choice. With your
    proposal it means I cannot do the very basic thing that works in
    every language with string interpolation:<br>
    std::string s =3D F&quot;% Hello %i World!&quot;;<br>
    auto s =3D F&quot;% Hello %i World!&quot;; // What is auto?<br>
    Any proposal that cannot get the above two lines to &quot;just work&quo=
t; with
    standard types is simply not good enough in my oppinion.<br>
    <br>
    I believe to make this work properly one needs some other
    infrastructure to exist first. There has to be a way to pass the
    expression to be formatted to some function that knows how to format
    it? Last time I used string interpolation was in Scala, where the
    literal prefix is actually the name of a function to call with the
    transformed string. I don&#39;t know whether we can ever introduce user
    defined string prefixes, but who knows. However, I think for now, a
    more flexible way is to combine both prefix and suffix. Let me try
    to explain with an example using your syntax where applicable:<br>
    <br>
    auto s =3D F&quot;% Hello %i World: %{x =3D=3D 1 ? &quot;a&quot; : &quo=
t;b&quot;}!&quot;_my_string;<br>
    <br>
    This is translated to something like:<br>
    auto&amp;&amp; __context =3D operator&quot;&quot;_my_string();<br>
    __context(&quot;Hello &quot;);<br>
    __context(i);<br>
    __context(&quot; World: &quot;);<br>
    __context(x =3D=3D 1 ? &quot;a&quot; : &quot;b&quot;); // Note the corr=
ect handling of
    literals inside %{ }<br>
    __context(&quot;!&quot;);<br>
    auto s =3D move(__context).get();d<br>
    <br>
    Whatever x this UDL returns must make the expression x(expr)
    well-formed for every expr that is an embedded expression of the
    string literal, or an actual string literal. Unfortunately this
    requires that a string literal with *only* the introducing prefix is
    ill-formed, unless we make the exception that a lacking suffix uses
    a standard-library context that produces a std::string (whether this
    is a good idea is debatable, but it sure as hell would be friggin&#39;
    convenient). Assuming no exceptions the get() method is invoked
    exactly once and therefore can use this knowledge to move the result
    out of the object. The move() helps to prefer an rvalue-qualified
    overload if one exists.<br>
    <br>
    The UDL is declared as usual but takes no parameters:<br>
    <br>
    MyStringBuilder operator&quot;&quot;_my_string();<br>
    <br>
    This suggests that the context cannot take constructor parameter,
    which may be a severe limitation. If constructor arguments are
    desirable then it would certainly need a syntax that distinguishes
    this UDL from others (or find a solution other than UDLs). An
    interpolated string that is used for a purpose other than being
    stored in some location (like performing output) it is more
    efficient to perform the output directly, which I guess is the
    motivation of using operator&lt;&lt;. A context that can take
    parameters could make this possible, for example using
    llvm::raw_ostream (a faster alternative to std::ostream):<br>
    <br>
    using namespace llvm;<br>
    raw_ostream out;<br>
    F&quot;% Hello %i World: %{x =3D=3D 1 ? &quot;a&quot; : &quot;b&quot;}!=
&quot;_raw_ostream{out};<br>
    <br>
    Using a wrapper around raw_ostream that uses operator() instead of
    operator&lt;&lt; can directly insert into the stream with zero
    overhead compared to a handwritten sequence of statements (same
    applies for std::ostream). What is weird about this syntax, though,
    is the placement of the &quot;thing&quot; that does the actual work at =
the end
    of the expression instead of the front as it were in a function
    call. Your approach with the receiving object at the front makes it
    at least *look* better. Maybe these can somehow be combined.<br>
    <br>
    Regardless of whether my approach here works or not, I think a
    solution that is not directly coupled to a certain operator (except
    the call operator) is less restricted and far more flexible.
    Function objects are way more common than insertion operators and
    maybe we can slow down the spreading abuse of operator&lt;&lt; . I
    know of some classes that could be an immediate drop-in and would
    &quot;just work&quot; with minimal adjustments. If the standard-provide=
d
    string context uses ADL-based lookup to (for example) to_string(x),
    or to_string(context, x), you have a convenient customization point
    to support the default string interpolation.<br>
    <br>
    (2) Even if you stick to operator&lt;&lt; I find it *very*
    disturbing that there is no &lt;&lt; between cout and the literal.<br>
    <br>
    cout F&quot;% ...&quot;; // Where&#39;s the operator? No call parens? A=
m I blind?
    Is the sky falling?<br>
    cout &lt;&lt; F&quot;% ...&quot;; // Ah, there it is!<br>
    <br>
    It also means that with your approach I couldn&#39;t pass the result of
    the interpolated literal as function parameter.<br>
    <br>
    foo(F&quot;% ...&quot;) // ill-formed: foo(&lt;&lt; &quot;...&quot;)<br=
>
    <br>
    (Which would be also ill-formed if the compiler can&#39;t find a
    matching operator&lt;&lt;, but that&#39;s a different issue.)<br>
    <br>
    It has to be as convenient and flexible as possible for the
    end-user.<br>
    <br>
    (3) I think it&#39;s very strange to have the escaping character be par=
t
    of the string literal. To me it lacks a clear separation between the
    actual literal content and the introducer. Look at raw literals:
    R&quot;delimiter(...)delimiter&quot; where there is a clearly visible
    distinction between &quot;content&quot; and &quot;non-content&quot;. No=
t sure how to do
    this properly, especially regarding the next point:<br>
    <br>
    (4) How does this combine with the other literal prefixes, like R?<br>
    <br>
    (5) There are actually two proposals in there: string interpolation
    and multiline literals. Those are completely orthogonal and you
    don&#39;t need the one to implement the other. You&#39;d be better off
    making these two separate (independent) proposals.<br>
    <br>
    <div>Am 18.09.2015 um 22:21 schrieb Andrew
      Tomazos:<br>
    </div>
    </div></div><blockquote type=3D"cite"><div><div class=3D"h5">
      <div dir=3D"ltr">Please find attached a very very rough draft of a
        proposal entitled &quot;Interpolated String Literals&quot;.
        <div><br>
        </div>
        <div>Mainly after encouragement or discouragement, and any
          high-level thoughts you might have about it.</div>
        <div><br>
        </div>
      </div>
      -- <br>
      <br>
      --- <br>
      You received this message because you are subscribed to the Google
      Groups &quot;ISO C++ Standard - Future Proposals&quot; group.<br></di=
v></div>
      To unsubscribe from this group and stop receiving emails from it,
      send an email to <a rel=3D"nofollow">std-proposal...@isocpp.org</a>.<=
br>
      To post to this group, send email to <a rel=3D"nofollow">std-pr...@is=
ocpp.org</a>.<span class=3D""><br>
      Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/=
group/std-proposals/" rel=3D"nofollow" target=3D"_blank">http://groups.goog=
le.com/a/isocpp.org/group/std-proposals/</a>.<br>
    </span></blockquote>
    <br>
  </div>

</blockquote></div></div><div class=3D""><div class=3D"h5">

<p></p>

-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</div></div></blockquote></div><br></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--089e0103009cd7c95505202d5c1d--

.
