Discussion:
[std-discussion] Why string_view->string is explicit?
TONGARI J
2017-03-14 08:15:27 UTC
Permalink
Creating a string from a string_view is not cheap, so it should be explicit
But given that we already have an implicit ctor that takes a char-pointer,
I don't think that argument makes sense (unless you also want to deprecate
that one).
I think the ease of use is more feasible than some unintuitive restriction.

Has this ever been discussed in the standard committee?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Tony V E
2017-03-14 11:56:39 UTC
Permalink
<html><head></head><body lang="en-US" style="background-color: rgb(255, 255, 255); line-height: initial;"> <div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);">We don't have guidelines for when to be implicit or explicit. I'm working on that. &nbsp;https://github.com/tvaneerd/isocpp/blob/master/conversions.md</div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);"><br></div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);">In addition to 'not cheap', the constructor could throw. ‎Throwing from 'unseen' code is (somewhat) harder to deal with.&nbsp;</div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);"><br></div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);">I think if we had string_view earlier, then string from char * probably would &nbsp;have been explicit as well.&nbsp;</div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);"><br></div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);">Last reason (I need to add this to my paper somewhere) -&nbsp;</div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);">we want to encourage string_view use, discourage string. Wherever you are doing that conversion, you should be thinking 'could I instead turn that string into a string_view?'</div><div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);"><br></div> <div style="width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);"><br></div> <div style="font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 255, 255);">Sent&nbsp;from&nbsp;my&nbsp;BlackBerry&nbsp;portable&nbsp;Babbage&nbsp;Device</div> <table width="100%" style="background-color:white;border-spacing:0px;"> <tbody><tr><td colspan="2" style="font-size: initial; text-align: initial; background-color: rgb(255, 255, 255);"> <div style="border-style: solid none none; border-top-color: rgb(181, 196, 223); border-top-width: 1pt; padding: 3pt 0in 0in; font-family: Tahoma, 'BB Alpha Sans', 'Slate Pro'; font-size: 10pt;"> <div><b>From: </b>TONGARI J</div><div><b>Sent: </b>Tuesday, March 14, 2017 4:15 AM</div><div><b>To: </b>ISO C++ Standard - Discussion</div><div><b>Reply To: </b>std-***@isocpp.org</div><div><b>Subject: </b>[std-discussion] Why string_view-&gt;string is explicit?</div></div></td></tr></tbody></table><div style="border-style: solid none none; border-top-color: rgb(186, 188, 209); border-top-width: 1pt; font-size: initial; text-align: initial; background-color: rgb(255, 255, 255);"></div><br><div id="_originalContent" style=""><div dir="ltr">P0254 does give a reason:<blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">Creating a string from a string_view is not cheap, so it should be explicit</blockquote><div><br></div><div>But given that we already have an implicit ctor that takes a char-pointer, I don't think that argument makes sense (unless you also want to deprecate that one).</div><div>I think the ease of use is more feasible than some unintuitive restriction.</div><div><br></div><div>Has this ever been discussed in the standard committee?</div></div>

<p></p>

-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="mailto:std-discussion+***@isocpp.org">std-discussion+***@isocpp.org</a>.<br>
To post to this group, send email to <a href="mailto:std-***@isocpp.org">std-***@isocpp.org</a>.<br>
Visit this group at <a href="https://groups.google.com/a/isocpp.org/group/std-discussion/">https://groups.google.com/a/isocpp.org/group/std-discussion/</a>.<br>
<br><!--end of _originalContent --></div></body></html>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &quot;ISO C++ Standard - Discussion&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="mailto:std-discussion+***@isocpp.org">std-discussion+***@isocpp.org</a>.<br />
To post to this group, send email to <a href="mailto:std-***@isocpp.org">std-***@isocpp.org</a>.<br />
Visit this group at <a href="https://groups.google.com/a/isocpp.org/group/std-discussion/">https://groups.google.com/a/isocpp.org/group/std-discussion/</a>.<br />
TONGARI J
2017-03-14 14:17:43 UTC
Permalink
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm working
on that. https://github.com/tvaneerd/isocpp/blob/master/conversions.md
In addition to 'not cheap', the constructor could throw. ‎Throwing from
'unseen' code is (somewhat) harder to deal with.
Well, copy ctor may throw as well...I really don't see a point here. I
don't think throw-ness or cheapness is a good criteria for explicit-ness.
It's better to judge by semantic.
Post by Tony V E
I think if we had string_view earlier, then string from char * probably
would have been explicit as well.
Last reason (I need to add this to my paper somewhere) -
we want to encourage string_view use, discourage string. Wherever you are
doing that conversion, you should be thinking 'could I instead turn that
string into a string_view?'
Frankly, I think a class that has a T::operator=(U) should have a
corresponding implicit T(U). It's more symmetric and consistent.

Look at what it is:
string_view sv(...);
string s = sv; // not allowed
s = sv; // allowed

A wat moment.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Vicente J. Botet Escriba
2017-03-14 18:07:45 UTC
Permalink
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm
working on that.
https://github.com/tvaneerd/isocpp/blob/master/conversions.md
<https://github.com/tvaneerd/isocpp/blob/master/conversions.md>
In addition to 'not cheap', the constructor could throw. ‎Throwing
from 'unseen' code is (somewhat) harder to deal with.
Well, copy ctor may throw as well...I really don't see a point here. I
don't think throw-ness or cheapness is a good criteria for explicit-ness.
It's better to judge by semantic.
Humm. I agree that if all interface requested a copy, then whether the
conversion throws wouldn't have any importance. However take this case

void f(T const&);

If I have a T t, I can call f(t) without copying it and of course with
no exception thrown. However if I have a U u that is implicitly
convertible to T, I could call f(u) but I will need to convert it and
then have possible exceptions.

Having an explicit conversion wouldn't compile and so the user would
need to analyze if she wants to do an explicit conversion that can cost
and throw.

f(T(u));

I agree that sometimes we want to be as transparent as possible, but I
don't believe having this conversion implicit is good. As Tony said, the
conversion from char const* should be as well explicit.
Post by Tony V E
I think if we had string_view earlier, then string from char *
probably would have been explicit as well.
Last reason (I need to add this to my paper somewhere) -
we want to encourage string_view use, discourage string. Wherever
you are doing that conversion, you should be thinking 'could I
instead turn that string into a string_view?'
Frankly, I think a class that has a T::operator=(U) should have a
corresponding implicit T(U). It's more symmetric and consistent.
I agree. IMO this merits a DR.
The assignment string::opetaror=(string_view) should be removed.

Vicente
Post by Tony V E
|
string_view sv(...);
strings =sv;// not allowed
s =sv;// allowed
|
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Tony V E
2017-03-14 18:22:42 UTC
Permalink
Post by TONGARI J
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm working
on that. https://github.com/tvaneerd/isocpp/blob/master/conversions.md
In addition to 'not cheap', the constructor could throw. ‎Throwing from
'unseen' code is (somewhat) harder to deal with.
Well, copy ctor may throw as well...I really don't see a point here. I
don't think throw-ness or cheapness is a good criteria for explicit-ness.
It's better to judge by semantic.
By what semantic? That type two types represent the "same thing", or
something else?
Post by TONGARI J
Post by Tony V E
I think if we had string_view earlier, then string from char * probably
would have been explicit as well.
Last reason (I need to add this to my paper somewhere) -
we want to encourage string_view use, discourage string. Wherever you are
doing that conversion, you should be thinking 'could I instead turn that
string into a string_view?'
Frankly, I think a class that has a T::operator=(U) should have a
corresponding implicit T(U). It's more symmetric and consistent.
string_view sv(...);
string s = sv; // not allowed
s = sv; // allowed
A wat moment.
That's a good point.
My conclusion from that might be that

string s = sv; // not allowed

should be allowed on explicit constructors.
(But I know changing that is a significant change).
Not just because it goes along with operator=, but because most devs
consider

string s = sv;

to be "the same as"

string s{sv};
--
Be seeing you,
Tony
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Vicente J. Botet Escriba
2017-03-14 18:56:56 UTC
Permalink
Post by Tony V E
We don't have guidelines for when to be implicit or explicit.
I'm working on that.
https://github.com/tvaneerd/isocpp/blob/master/conversions.md
<https://github.com/tvaneerd/isocpp/blob/master/conversions.md>
In addition to 'not cheap', the constructor could throw.
‎Throwing from 'unseen' code is (somewhat) harder to deal with.
Well, copy ctor may throw as well...I really don't see a point
here. I don't think throw-ness or cheapness is a good criteria for
explicit-ness.
It's better to judge by semantic.
By what semantic? That type two types represent the "same thing", or
something else?
I think if we had string_view earlier, then string from char *
probably would have been explicit as well.
Last reason (I need to add this to my paper somewhere) -
we want to encourage string_view use, discourage string.
Wherever you are doing that conversion, you should be thinking
'could I instead turn that string into a string_view?'
Frankly, I think a class that has a T::operator=(U) should have a
corresponding implicit T(U). It's more symmetric and consistent.
|
string_view sv(...);
strings =sv;// not allowed
s =sv;// allowed
|
A wat moment.
That's a good point.
My conclusion from that might be that
|strings =sv;// not allowed
|
should be allowed on explicit constructors.
(But I know changing that is a significant change).
Not just because it goes along with operator=, but because most devs
consider
|strings =sv;
|to be "the same as"
|strings{sv};
|
I must to admit that this is the case and I agree with you that the
current status is confusing. Many people say "Why

|strings =sv;|

is not explicit enough?"



However until we change this the operator= shouldn't be defined if the
conversion is explicit.

Tony, I believe that this could be added to the recommendations of your
paper. What do you think?

Vicente

Vicente
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-14 19:00:10 UTC
Permalink
On 14 March 2017 at 20:56, Vicente J. Botet Escriba
I must to admit that this is the case and I agree with you that the current
status is confusing. Many people say "Why
string s = sv;
is not explicit enough?"
There's existing code that relies on that not invoking an explicit
constructor, that's why.
However until we change this the operator= shouldn't be defined if the
conversion is explicit.
Shouldn't be defined where? Anywhere? That seems like a quick
conclusion without rationale to back it up.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-14 19:55:30 UTC
Permalink
Post by Ville Voutilainen
On 14 March 2017 at 20:56, Vicente J. Botet Escriba
Post by Vicente J. Botet Escriba
I must to admit that this is the case and I agree with you that the
current
Post by Vicente J. Botet Escriba
status is confusing. Many people say "Why
string s = sv;
is not explicit enough?"
There's existing code that relies on that not invoking an explicit
constructor, that's why.
To go into further detail, consider the following:

struct Temp
{
Temp(float) {}
explicit Temp(int) {}
};

Temp t = 5;

That is currently valid code, but it will call the `float` version. If you
change this to use the direct-initialization rules instead of
copy-initialization rules, then it will call the `explicit` constructor,
and therefore not be a backwards compatible change.

So to make this work backwards compatibly, you would have to create another
initialization type, which is neither direct nor copy, but which works like
copy-initialization save for the fact that if it fails to find a
non-explicit constructor, it then looks for an explicit one.

And as much as I like the general idea behind this, I would much rather not
add additional complications to initialization forms.

It should be noted that this is a difference between copy-initialization
and copy-list-initialization. The former never considers `explicit`
constructors, while the latter fails if an explicit constructor is
selected. So `Temp t = {5};` is currently il-formed. And therefore, it
would be a backwards compatible change to make `Temp t = {5};` into
direct-list-initialization, since all ambiguous cases would have been
il-formed.
Post by Ville Voutilainen
However until we change this the operator= shouldn't be defined if the
Post by Vicente J. Botet Escriba
conversion is explicit.
Shouldn't be defined where? Anywhere? That seems like a quick
conclusion without rationale to back it up.
The idea being that for any type `T`, and for any value `u`, if `T t = u`
is valid, then `t = u` should also be valid. And if `t = u` is not valid,
then `T t = u` should also not be valid.

To do otherwise is highly inconsistent. Though in this case, quite useful.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Vicente J. Botet Escriba
2017-03-14 21:57:24 UTC
Permalink
Post by Ville Voutilainen
On 14 March 2017 at 20:56, Vicente J. Botet Escriba
Post by Vicente J. Botet Escriba
I must to admit that this is the case and I agree with you that
the current
Post by Vicente J. Botet Escriba
status is confusing. Many people say "Why
string s = sv;
is not explicit enough?"
There's existing code that relies on that not invoking an explicit
constructor, that's why.
|
structTemp
{
Temp(float){}
explicitTemp(int){}
};
Tempt =5;
|
That is currently valid code, but it will call the `float` version. If
you change this to use the direct-initialization rules instead of
copy-initialization rules, then it will call the `explicit`
constructor, and therefore not be a backwards compatible change.
Thanks for the example. Note that I'm not proposing it. I didn't know of
a case where changing this could break. The example is weird and I don't
see a real case where this could be useful, but I suspect there should
be code like this one on the field.
Post by Ville Voutilainen
So to make this work backwards compatibly, you would have to create
another initialization type, which is neither direct nor copy, but
which works like copy-initialization save for the fact that if it
fails to find a non-explicit constructor, it then looks for an
explicit one.
And as much as I like the general idea behind this, I would much
rather not add additional complications to initialization forms.
I believe we agree all here.
Post by Ville Voutilainen
It should be noted that this is a difference between
copy-initialization and copy-list-initialization. The former never
considers `explicit` constructors, while the latter fails if an
explicit constructor is selected. So `Temp t = {5};` is currently
il-formed. And therefore, it would be a backwards compatible change to
make `Temp t = {5};` into direct-list-initialization, since all
ambiguous cases would have been il-formed.
Post by Vicente J. Botet Escriba
However until we change this the operator= shouldn't be defined
if the
Post by Vicente J. Botet Escriba
conversion is explicit.
Shouldn't be defined where? Anywhere? That seems like a quick
conclusion without rationale to back it up.
The idea being that for any type `T`, and for any value `u`, if `T t =
u` is valid, then `t = u` should also be valid. And if `t = u` is not
valid, then `T t = u` should also not be valid.
To do otherwise is highly inconsistent. Though in this case, quite useful.
This is exactly my concern and I don't believe the assignment is useful.
Think of chrono::duaration, do we expect it to be assignable from its
representation?

Vicente
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
TONGARI J
2017-03-15 02:49:06 UTC
Permalink
On Wednesday, March 15, 2017 at 5:57:26 AM UTC+8, Vicente J. Botet Escriba
Post by Nicol Bolas
The idea being that for any type `T`, and for any value `u`, if `T t = u`
is valid, then `t = u` should also be valid. And if `t = u` is not valid,
then `T t = u` should also not be valid.
To do otherwise is highly inconsistent. Though in this case, quite useful.
This is exactly my concern and I don't believe the assignment is useful.
It's useful performance-wise. Such an assignment could reuse the allocated
memory.
My preference is to remove the explicit restriction from the ctor, instead
of adding another restriction by removing the assignment.

I don't think trading the ease-of-use and performance for some imaginary
safety is worthwhile, after all, we're in C++.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-22 07:56:07 UTC
Permalink
Post by TONGARI J
On Wednesday, March 15, 2017 at 5:57:26 AM UTC+8, Vicente J. Botet Escriba
Post by Nicol Bolas
The idea being that for any type `T`, and for any value `u`, if `T t = u`
is valid, then `t = u` should also be valid. And if `t = u` is not valid,
then `T t = u` should also not be valid.
To do otherwise is highly inconsistent. Though in this case, quite useful.
This is exactly my concern and I don't believe the assignment is useful.
It's useful performance-wise. Such an assignment could reuse the allocated
memory.
My preference is to remove the explicit restriction from the ctor, instead
of adding another restriction by removing the assignment.
I don't think trading the ease-of-use and performance for some imaginary
safety is worthwhile, after all, we're in C++.
*I am re-posting here and deleting my original post, as I didn't realise my
thread was a duplicate.*

With regard to this post
<https://groups.google.com/a/isocpp.org/forum/#%21topic/std-proposals/5vAS9BkHNKA>,
I have noticed that the inability of `string_view` to convert to `string`
causes a problem when considering interoperation with hypothetical
heterogeneous associative container modifiers, such as:

template <typename K>
T& map::operator[](K const& k);

A natural requirement of this operator is that `is_convertible_v<K,
key_type>` be `true`. However, to support use of `string_view` (my
motivating use case) with this operator, the requirement must be weakened
to `is_constructible_v<key_type, K>` being `true`. This seems wrong, yet it
seems natural that `string_view` should be usable as a key.

Why is `string_view` not convertible to `string`? I have found this
discussion
<https://groups.google.com/a/isocpp.org/forum/#%21topic/std-proposals/5vAS9BkHNKA>
from 2014 where Matthew Fioravante gives this rationale:

Converting a string to a string_view is not really a conversion, its more
Post by TONGARI J
like constructing a reference to the data which performance wise is
basically free (and possibly even more optimal then passing const string&
because we don't have that extra indirection). The assignment is a shallow
copy, similar to converting a child class pointer to a base class pointer.
Converting from string_view to string however is a real data conversion.
Memory has to be allocated and a copy of the data has to be made. In this
case its better to have an explicit conversion so that people are prevented
from easy to write hidden pessimizations. It marks in the code directly
where copies of strings are being made.
I don't find this reasoning convincing. The same logic could be applied to
conversion of `char const*` to `string`, yet this is permitted. Is the
opinion of the committee that conversion of `char const*` to `string` was a
mistake? As an example, say I have a function:

void f(string);

I can call this function in three ways:

f(s1); // `decltype(s1)` is `char const*`
f(s2); // `decltype(s2)` is `string`
f(s3); // `decltype(s3)` is `string_view`

In each of these cases, an allocation and a copy is made, but only in the
case of `string_view` is the programmer made explicitly aware of this. Even
if the function looks like this instead:

void f(string const&);

There is still an allocation and a copy made in the `char const*` case. And
in this case, I would say that the function should be updated like so:

void f(string_view);

This way no allocations or copies are made.

Also, if `string_view` should be thought of as a reference-like type, does
that mean that conversion from `T&` to `T` should be explicit?

In my opinion, it the responsibility of the owner an object to be aware of
when potentially expensive copies are being made. The distinction between
implicit and explicit conversion should be made on the basis of safety and
correctness, not performance. Disallowing conversion from `string_view` to
`string` makes `string_view` awkward to use, which may discourage people
from using it -- a net loss in my view. The usability of a type should not
be hamstrung because of a fear that users might not aware of the
performance costs of certain operations.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-22 13:06:53 UTC
Permalink
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware of
when potentially expensive copies are being made. The distinction between
implicit and explicit conversion should be made on the basis of safety and
correctness, not performance. Disallowing conversion from `string_view`
to `string` makes `string_view` awkward to use, which may discourage
people from using it -- a net loss in my view. The usability of a type
should not be hamstrung because of a fear that users might not aware of the
performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing an
explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.

And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them to
`std::string`s; they're for APIs where you don't need to modify the string.

People use C++ because they want performance. We should do what we can to
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-23 01:45:57 UTC
Permalink
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which may
discourage people from using it -- a net loss in my view. The usability of
a type should not be hamstrung because of a fear that users might not aware
of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing an
explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
Post by Nicol Bolas
And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them to
`std::string`s; they're for APIs where you don't need to modify the string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.

People use C++ because they want performance. We should do what we can to
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many. Disallowing conversion from
`string_view` to `string` is not making the fast path the default; it is
disabling the default path because it has been deemed too slow. I have no
idea why this conversion has been singled out in this regard; consider the
following:

string s;
string_view sv = s;

string s1 = s; // okay
string s2 = sv; // error

These operations do the *same* exact thing. Why is one allowed and the
other isn't? This is inconsistent. It makes no sense.

As another example of how requiring *explicit* conversion in this case is
wrong, consider a programmer who is using a 3rd party library with the
following function:

void frobnicate(std::string const& s);

The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he calls
`frobnicate`, he has to add an explicit conversion to `string`:

frobnicate(std::string(sv))

Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified. At some point in the future, the programmer switches to a new
version of the 3rd party library, which has updated its interfaces to
support `string_view`. To avoid breaking user code, extra overloads of the
`frobnicate` function have been added:

void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);

Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.

The problem here is that the explicit cast to `string` has suppressed the
type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-23 06:02:04 UTC
Permalink
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which may
discourage people from using it -- a net loss in my view. The usability of
a type should not be hamstrung because of a fear that users might not aware
of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing
an explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
And furthermore, if you have so many conversions from `string_view` to
Post by j***@gmail.com
Post by Nicol Bolas
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them to
`std::string`s; they're for APIs where you don't need to modify the string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
If that's the case, how can you claim that not having this implicit
constructor "violates their expectations". It violates *your* expectations,
but maybe users have requirements that do not align with your expectations.

People use C++ because they want performance. We should do what we can to
Post by j***@gmail.com
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many.
Yes, it is. But that's no excuse for dismissing it.

Disallowing conversion from `string_view` to `string` is not making the
Post by j***@gmail.com
fast path the default; it is disabling the default path because it has been
deemed too slow.
That is too much like assuming your own conclusion. By declaring the
conversion from `string_view` to `std::string` to be "the default path",
you're starting from the assumption that the conversion ought to be
implicit, then creating a framework that says that being explicit is wrong.

I have no idea why this conversion has been singled out in this regard;
Post by j***@gmail.com
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing.
One converts one object to another type. The other copies an object. They
only do "the same exact thing" on a conceptual level (copying a string); at
a language level, they're quite different. If the user wanted to live at
the conceptual level, they wouldn't have created a `string_view` at all.

A `string_view` is not a string; it is a view of a string; it's a range
with features. And a range is not a container. There is no implicit
conversion from ranges to containers (well technically, the iterator pair
constructors are not marked `explicit`), and nor should there be. So if
ranges don't have implicit conversions to containers, why should
`string_view` have implicit conversions to `string`?

You can consider this all to be sophistry to some users. And that may well
be the case. But the distinction undeniably *exists*. So who is to say that
the users who ignore the distinction are more correct than those who
recognize it?

Why is one allowed and the other isn't? This is inconsistent. It makes no
Post by j***@gmail.com
sense.
As another example of how requiring *explicit* conversion in this case is
wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified.
To get the full benefits from types like `string_view`, you have to use
them everywhere. Which means that, if you have to talk to libraries that
don't use `string_view`, then you are probably not going to be better off
by using it.

So "cannot be helped" is a strong statement. It can be helped (depending on
where `sv` comes from); you may simply need to reconsider your desire to
use `string_view`. I've encountered such problems in the past, where I
tried to switch to `string_view`, but realized that I would have to copy
*more* than if I just used `std::string`, thanks to frequent use of some
APIs that used `string`.
Post by j***@gmail.com
At some point in the future, the programmer switches to a new version of
the 3rd party library, which has updated its interfaces to support
`string_view`. To avoid breaking user code, extra overloads of the
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
That's a fair point. But it still has to be weighed against the performance
issue: do we want to make costly operations appear cheap? Which is more
important: future performance, or current performance due to misusing
implicit conversions?

Also, the writer of this library should have [[deprecated]] the `const
string&` overload, which would give users a warning when they use it. That
should be done regardless of what `string_view` does. After all, if I'm
using a home-grown string type, it's much more performance-friendly for me
to create a `string_view` than to copy to a `std::string`. So I'd want a
warning to happen once the performance-friendly API is available.

So it seems to me that this problem would be sorted out soon enough.

The problem here is that the explicit cast to `string` has suppressed the
Post by j***@gmail.com
type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
... huh? How can you say performance shouldn't be a consideration when you *just
showed* how not having this implicit conversion could negatively impact
performance?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-23 08:30:41 UTC
Permalink
Post by Nicol Bolas
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing
an explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
And furthermore, if you have so many conversions from `string_view` to
Post by j***@gmail.com
Post by Nicol Bolas
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
If that's the case, how can you claim that not having this implicit
constructor "violates their expectations". It violates *your*
expectations, but maybe users have requirements that do not align with your
expectations.
A `string_view` is like a more flexible `string const&`. They are
conceptually the same thing. It is natural to expect `string_view` to
convert to `string`, just as `string const&` does. The feature has been
disabled because it has been decided that if someone has a `string_view`,
then they probably want to avoid making deep copies. I'm unwilling to make
this assumption.
Post by Nicol Bolas
People use C++ because they want performance. We should do what we can to
Post by j***@gmail.com
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many.
Yes, it is. But that's no excuse for dismissing it.
Disallowing conversion from `string_view` to `string` is not making the
Post by j***@gmail.com
fast path the default; it is disabling the default path because it has been
deemed too slow.
That is too much like assuming your own conclusion. By declaring the
conversion from `string_view` to `std::string` to be "the default path",
you're starting from the assumption that the conversion ought to be
implicit, then creating a framework that says that being explicit is wrong.
What is the default path for changing one two to another if not a
conversion? Conversion from `string_view` to `string` inherently involves a
deep copy. We cannot make it any faster; we can only disable it altogether.

I have no idea why this conversion has been singled out in this regard;
Post by Nicol Bolas
Post by j***@gmail.com
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing.
One converts one object to another type. The other copies an object. They
only do "the same exact thing" on a conceptual level (copying a string); at
a language level, they're quite different. If the user wanted to live at
the conceptual level, they wouldn't have created a `string_view` at all.
A `string_view` is not a string; it is a view of a string; it's a range
with features. And a range is not a container. There is no implicit
conversion from ranges to containers (well technically, the iterator pair
constructors are not marked `explicit`), and nor should there be. So if
ranges don't have implicit conversions to containers, why should
`string_view` have implicit conversions to `string`?
I disagree. A `string_view` is conceptually the same thing as a `string
const`. They should support the same basic operations. The only difference
is that one owns the underlying data. Conversely, a range is simply
something that can be iterated over, while a container could be any number
of things. If you enabled conversion from range to container, you would
enable things like conversion of a `map` to a `vector`. A `map` is not the
same thing as a `vector`. They are totally different data structures
supporting different operations. `string_view` and `string` are the same
kind of thing; they (should) support the same operations.

You can consider this all to be sophistry to some users. And that may well
Post by Nicol Bolas
be the case. But the distinction undeniably *exists*. So who is to say
that the users who ignore the distinction are more correct than those who
recognize it?
Why is one allowed and the other isn't? This is inconsistent. It makes no
Post by Nicol Bolas
Post by j***@gmail.com
sense.
As another example of how requiring *explicit* conversion in this case
is wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified.
To get the full benefits from types like `string_view`, you have to use
them everywhere. Which means that, if you have to talk to libraries that
don't use `string_view`, then you are probably not going to be better off
by using it.
So "cannot be helped" is a strong statement. It can be helped (depending
on where `sv` comes from); you may simply need to reconsider your desire to
use `string_view`. I've encountered such problems in the past, where I
tried to switch to `string_view`, but realized that I would have to copy
*more* than if I just used `std::string`, thanks to frequent use of some
APIs that used `string`.
Refactoring to use a new feature is generally a gradual process. In a large
code base, it is impractical to change everything at once. By "cannot be
helped", I mean that the programmer cannot personally refactor the
interfaces of the library. Maybe he reported an issue with the library
maintainer, and went ahead with the refactor because it would result in net
performance gains despite the rough edges.

At some point in the future, the programmer switches to a new version of
Post by Nicol Bolas
Post by j***@gmail.com
the 3rd party library, which has updated its interfaces to support
`string_view`. To avoid breaking user code, extra overloads of the
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
That's a fair point. But it still has to be weighed against the
performance issue: do we want to make costly operations appear cheap? Which
is more important: future performance, or current performance due to
misusing implicit conversions?
Also, the writer of this library should have [[deprecated]] the `const
string&` overload, which would give users a warning when they use it. That
should be done regardless of what `string_view` does. After all, if I'm
using a home-grown string type, it's much more performance-friendly for me
to create a `string_view` than to copy to a `std::string`. So I'd want a
warning to happen once the performance-friendly API is available.
So it seems to me that this problem would be sorted out soon enough.
The problem here is that the explicit cast to `string` has suppressed the
Post by j***@gmail.com
type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
... huh? How can you say performance shouldn't be a consideration when you *just
showed* how not having this implicit conversion could negatively impact
performance?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-23 08:40:59 UTC
Permalink
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be
aware of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor
of `std::string` just because it doesn't implicitly convert to
`std::string` is a programmer who doesn't *deserve* to have
`string_view`. Providing an explicit conversion requires minimal effort on
the caller's part; it is hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
And furthermore, if you have so many conversions from `string_view` to
Post by j***@gmail.com
Post by Nicol Bolas
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
If that's the case, how can you claim that not having this implicit
constructor "violates their expectations". It violates *your*
expectations, but maybe users have requirements that do not align with your
expectations.
A `string_view` is like a more flexible `string const&`. They are
conceptually the same thing. It is natural to expect `string_view` to
convert to `string`, just as `string const&` does. The feature has been
disabled because it has been decided that if someone has a `string_view`,
then they probably want to avoid making deep copies. I'm unwilling to make
this assumption.
Post by Nicol Bolas
People use C++ because they want performance. We should do what we can to
Post by j***@gmail.com
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many.
Yes, it is. But that's no excuse for dismissing it.
Disallowing conversion from `string_view` to `string` is not making the
Post by j***@gmail.com
fast path the default; it is disabling the default path because it has been
deemed too slow.
That is too much like assuming your own conclusion. By declaring the
conversion from `string_view` to `std::string` to be "the default path",
you're starting from the assumption that the conversion ought to be
implicit, then creating a framework that says that being explicit is wrong.
What is the default path for changing one two to another if not a
conversion? Conversion from `string_view` to `string` inherently involves a
deep copy. We cannot make it any faster; we can only disable it altogether.
I have no idea why this conversion has been singled out in this regard;
Post by Nicol Bolas
Post by j***@gmail.com
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing.
One converts one object to another type. The other copies an object. They
only do "the same exact thing" on a conceptual level (copying a string); at
a language level, they're quite different. If the user wanted to live at
the conceptual level, they wouldn't have created a `string_view` at all.
A `string_view` is not a string; it is a view of a string; it's a range
with features. And a range is not a container. There is no implicit
conversion from ranges to containers (well technically, the iterator pair
constructors are not marked `explicit`), and nor should there be. So if
ranges don't have implicit conversions to containers, why should
`string_view` have implicit conversions to `string`?
I disagree. A `string_view` is conceptually the same thing as a `string
const`. They should support the same basic operations. The only difference
is that one owns the underlying data. Conversely, a range is simply
something that can be iterated over, while a container could be any number
of things. If you enabled conversion from range to container, you would
enable things like conversion of a `map` to a `vector`. A `map` is not the
same thing as a `vector`. They are totally different data structures
supporting different operations. `string_view` and `string` are the same
kind of thing; they (should) support the same operations.
You can consider this all to be sophistry to some users. And that may well
Post by Nicol Bolas
be the case. But the distinction undeniably *exists*. So who is to say
that the users who ignore the distinction are more correct than those who
recognize it?
Why is one allowed and the other isn't? This is inconsistent. It makes no
Post by Nicol Bolas
Post by j***@gmail.com
sense.
As another example of how requiring *explicit* conversion in this case
is wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified.
To get the full benefits from types like `string_view`, you have to use
them everywhere. Which means that, if you have to talk to libraries that
don't use `string_view`, then you are probably not going to be better off
by using it.
So "cannot be helped" is a strong statement. It can be helped (depending
on where `sv` comes from); you may simply need to reconsider your desire to
use `string_view`. I've encountered such problems in the past, where I
tried to switch to `string_view`, but realized that I would have to copy
*more* than if I just used `std::string`, thanks to frequent use of some
APIs that used `string`.
Refactoring to use a new feature is generally a gradual process. In a
large code base, it is impractical to change everything at once. By "cannot
be helped", I mean that the programmer cannot personally refactor the
interfaces of the library. Maybe he reported an issue with the library
maintainer, and went ahead with the refactor because it would result in net
performance gains despite the rough edges.
At some point in the future, the programmer switches to a new version of
Post by Nicol Bolas
Post by j***@gmail.com
the 3rd party library, which has updated its interfaces to support
`string_view`. To avoid breaking user code, extra overloads of the
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to
a `string` wherever he calls `frobnicate`, he experiences no
performance increase. If conversion from `string_view` to `string` *had*
been supported, this would not have been the case, and the performance of
the programmer's code would have returned to its pre-`string_view`
state.
That's a fair point. But it still has to be weighed against the
performance issue: do we want to make costly operations appear cheap? Which
is more important: future performance, or current performance due to
misusing implicit conversions?
I think enabling conversions that are conceptually correct and safe,
avoiding casts wherever possible, and relying on the type system as much as
possible is what is important. Performance can be addressed on a
case-by-case basis by individual users by profiling. Disabling this
conversion seems kind of like library designers prematurely optimizing user
code.
Post by j***@gmail.com
Also, the writer of this library should have [[deprecated]] the `const
Post by Nicol Bolas
string&` overload, which would give users a warning when they use it. That
should be done regardless of what `string_view` does. After all, if I'm
using a home-grown string type, it's much more performance-friendly for me
to create a `string_view` than to copy to a `std::string`. So I'd want a
warning to happen once the performance-friendly API is available.
So it seems to me that this problem would be sorted out soon enough.
This is a fair point, but it would have the side effect of flagging all
calls to `frobnicate` with a `string` as deprecated. This would require the
user to cast each `string` to a `string_view` which, while not as egregious
as the inverse, is still not great.
Post by j***@gmail.com
The problem here is that the explicit cast to `string` has suppressed the
Post by Nicol Bolas
Post by j***@gmail.com
type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
... huh? How can you say performance shouldn't be a consideration when
you *just showed* how not having this implicit conversion could
negatively impact performance?
The criteria for determining whether a conversion should be supported
should not include performance considerations. I was just showing how
disabling the conversion can adversely affect performance. Even if this
weren't the case, my view would be the same.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-23 16:03:51 UTC
Permalink
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be
aware of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor
of `std::string` just because it doesn't implicitly convert to
`std::string` is a programmer who doesn't *deserve* to have
`string_view`. Providing an explicit conversion requires minimal effort on
the caller's part; it is hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
And furthermore, if you have so many conversions from `string_view` to
Post by j***@gmail.com
Post by Nicol Bolas
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
If that's the case, how can you claim that not having this implicit
constructor "violates their expectations". It violates *your*
expectations, but maybe users have requirements that do not align with your
expectations.
A `string_view` is like a more flexible `string const&`. They are
conceptually the same thing. It is natural to expect `string_view` to
convert to `string`, just as `string const&` does. The feature has been
disabled because it has been decided that if someone has a `string_view`,
then they probably want to avoid making deep copies. I'm unwilling to make
this assumption.
No, the implicit conversion is disabled because your initial perspective on
`string_view` is incorrect. `string_view` is not "a more flexible `string
const &`. It is a range of a string. Yes, it has string-specific
interfaces, but that doesn't change the fact that it is not a *container*.
It's just a range.

And ranges are *not* implicitly convertible to containers.

People use C++ because they want performance. We should do what we can to
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many.
Yes, it is. But that's no excuse for dismissing it.
Disallowing conversion from `string_view` to `string` is not making the
Post by j***@gmail.com
fast path the default; it is disabling the default path because it has been
deemed too slow.
That is too much like assuming your own conclusion. By declaring the
conversion from `string_view` to `std::string` to be "the default path",
you're starting from the assumption that the conversion ought to be
implicit, then creating a framework that says that being explicit is wrong.
What is the default path for changing one two to another if not a
conversion? Conversion from `string_view` to `string` inherently involves a
deep copy. We cannot make it any faster; we can only disable it altogether.
If "the default path" is conversion, then why is making conversion explicit
"disabling the default path"? An explicit conversion is still a conversion;
you just have to *ask for it*.

I don't know why you insist on calling explicit conversions "disabled".
"Disabled" would mean "you can't do it," not "it requires more text".
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-23 16:19:59 UTC
Permalink
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be
aware of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor
of `std::string` just because it doesn't implicitly convert to
`std::string` is a programmer who doesn't *deserve* to have
`string_view`. Providing an explicit conversion requires minimal effort on
the caller's part; it is hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
And furthermore, if you have so many conversions from `string_view` to
Post by j***@gmail.com
Post by Nicol Bolas
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
If that's the case, how can you claim that not having this implicit
constructor "violates their expectations". It violates *your*
expectations, but maybe users have requirements that do not align with your
expectations.
A `string_view` is like a more flexible `string const&`. They are
conceptually the same thing. It is natural to expect `string_view` to
convert to `string`, just as `string const&` does. The feature has been
disabled because it has been decided that if someone has a `string_view`,
then they probably want to avoid making deep copies. I'm unwilling to make
this assumption.
No, the implicit conversion is disabled because your initial perspective on
`string_view` is incorrect. `string_view` is not "a more flexible `string
const &`. It is a range of a string. Yes, it has string-specific
interfaces, but that doesn't change the fact that it is not a *container*.
It's just a range.

And ranges are *not* implicitly convertible to containers.


A `string` is a range too. A range is just a type that defines `std::begin`
and `std::end` (this may or may not be technically correct, but you get my
point). If `string_view` looks and behaves like a "string", then it is a
string.


People use C++ because they want performance. We should do what we can to
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many.
Yes, it is. But that's no excuse for dismissing it.
Disallowing conversion from `string_view` to `string` is not making the
Post by j***@gmail.com
fast path the default; it is disabling the default path because it has been
deemed too slow.
That is too much like assuming your own conclusion. By declaring the
conversion from `string_view` to `std::string` to be "the default path",
you're starting from the assumption that the conversion ought to be
implicit, then creating a framework that says that being explicit is wrong.
What is the default path for changing one two to another if not a
conversion? Conversion from `string_view` to `string` inherently involves a
deep copy. We cannot make it any faster; we can only disable it altogether.
If "the default path" is conversion, then why is making conversion explicit
"disabling the default path"? An explicit conversion is still a conversion;
you just have to *ask for it*.

I don't know why you insist on calling explicit conversions "disabled".
"Disabled" would mean "you can't do it," not "it requires more text".


Conversions are implicit. I did use the term "explicit conversion", but
this isn't really a thing. An "explicit conversion" is a construction, and
construction syntax is unfortunately the same as type casting syntax
(unless you use uniform initialization syntax, which is its own can of
worms). Conversion is the natural way to convert one type to another.
Conversion from `string_view` to `string` is currently disabled. To perform
the"conversion" you must explicitly invoke the constructor/perform a your
cast.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
i***@gmail.com
2017-03-23 21:20:07 UTC
Permalink
Post by Nicol Bolas
Post by Nicol Bolas
Why is one allowed and the other isn't? This is inconsistent. It makes no
sense.
As another example of how requiring *explicit* conversion in this case
is wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified.
To get the full benefits from types like `string_view`, you have to use
them everywhere. Which means that, if you have to talk to libraries that
don't use `string_view`, then you are probably not going to be better off
by using it.
So "cannot be helped" is a strong statement. It can be helped (depending
on where `sv` comes from); you may simply need to reconsider your desire to
use `string_view`. I've encountered such problems in the past, where I
tried to switch to `string_view`, but realized that I would have to copy
*more* than if I just used `std::string`, thanks to frequent use of some
APIs that used `string`.
Post by Nicol Bolas
At some point in the future, the programmer switches to a new version of
the 3rd party library, which has updated its interfaces to support
`string_view`. To avoid breaking user code, extra overloads of the
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
That's a fair point. But it still has to be weighed against the
performance issue: do we want to make costly operations appear cheap? Which
is more important: future performance, or current performance due to
misusing implicit conversions?
Also, the writer of this library should have [[deprecated]] the `const
string&` overload, which would give users a warning when they use it. That
should be done regardless of what `string_view` does. After all, if I'm
using a home-grown string type, it's much more performance-friendly for me
to create a `string_view` than to copy to a `std::string`. So I'd want a
warning to happen once the performance-friendly API is available.
Another way to have cake and eat cake is introduce helper function that
will allow implicit cast even if explicit is only available:

#include<vector>

template<typename T>
struct Implicit_Impl
{
T t; //probably "&" would be best there

template<typename TT>
operator TT()
{
return TT(std::move(t));
}
};

template<typename T>
Implicit_Impl<T> implicit_cast(T&& t)
{
return { std::forward<T>(t) };
}

std::vector<int> i = { 5.5, 5.7, }; //error!
std::vector<int> j = { implicit_cast(5.5), implicit_cast(5.7), }; //ok

But probably this is not most sane thing to do because explicit
constructors have great value on its own and exist for the reason.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Hodges
2017-03-23 09:46:13 UTC
Permalink
Post by j***@gmail.com
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he calls
`frobnicate`, *he has to add an explicit conversion* to `string`

I would have to say "good" at this point. My reasoning is as follows:

There seems to me to be a logical equivalence when creating a string_view
from a string. I.e. the string_view is a view of the string.

Creating a string from a string_view does not infer the same equivalence -
I think the correct term is that the operation is not associative. A.B is
not the same as B.A. This conversion actually constructs a new copy, not a
view or reference. It is a different kind of operation.

In my view, statement of intent of this copy should be explicit, as it has
side-effects. (i.e. the two objects are now unrelated).
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which may
discourage people from using it -- a net loss in my view. The usability of
a type should not be hamstrung because of a fear that users might not aware
of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing
an explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
Post by Nicol Bolas
And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them to
`std::string`s; they're for APIs where you don't need to modify the string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
People use C++ because they want performance. We should do what we can to
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many. Disallowing conversion from
`string_view` to `string` is not making the fast path the default; it is
disabling the default path because it has been deemed too slow. I have no
idea why this conversion has been singled out in this regard; consider the
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing. Why is one allowed and the
other isn't? This is inconsistent. It makes no sense.
As another example of how requiring *explicit* conversion in this case is
wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified. At some point in the future, the programmer switches to a new
version of the 3rd party library, which has updated its interfaces to
support `string_view`. To avoid breaking user code, extra overloads of
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
The problem here is that the explicit cast to `string` has suppressed the
type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-23 15:41:46 UTC
Permalink
Post by j***@gmail.com
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he calls
`frobnicate`, *he has to add an explicit conversion* to `string`

I would have to say "good" at this point. My reasoning is as follows:

There seems to me to be a logical equivalence when creating a string_view
from a string. I.e. the string_view is a view of the string.

Creating a string from a string_view does not infer the same equivalence -
I think the correct term is that the operation is not associative. A.B is
not the same as B.A. This conversion actually constructs a new copy, not a
view or reference. It is a different kind of operation.


You are talking about commutativity. However, this concept can only be
applied to binary operations. A type conversion is not a binary operation;
it is a mapping.

If you want to establish a mathematical basis for type conversions, you
probably want to look at the concept of homomorphisms. A homomorphism is a
structure-preserving mapping between two algebraic structures of the same
type. For example, if you have a homomorphism, f : A -> B, that maps
structure A to structure B, it will preserve the operations. For example,
if A and B define addition then, given every pair of elements of A, x and y:

f(x + y) = f(x) + f(y)

If you apply this concept to the C++ type system, `A` and `B` are types
that meet the requirements of a shared concept, and the homomorphism `f` is
the conversion from `A` to `B`.

In our case, `string_view` and `string` are both conceptually "strings"
(they are the same kind of thing), and a conversion (homomorphism) does
exist from `string_view` to `string`, because the conversion maintains the
string operations (e.g. `length`, `substr`, `operator[]`, `operator+`). In
fact, a two-way conversion (isomorphism) between `string_view` and `string`
exists because `string` can also convert to `string_view` (which cannot be
said for other related pairs of types, like `int` and `short`).

Of course, exceptions throw a spanner in the works, because there is no
mathematical analogue (to my knowledge). I strongly believe that
conversions should be allowed to throw. This way, conversion can be allowed
for a partial mapping, f, where f(x) is undefined for some values of x (for
example, Robert Ramey's proposed Boost Safe Numerics library uses
exceptions like this to great effect, where for example, conversion from
`safe<long>` to `safe<short>` is permitted but may throw).

Conversion of value semantic types is a mathematical concept. Performance
concerns should not factor into the equation.

In my view, statement of intent of this copy should be explicit, as it has
side-effects. (i.e. the two objects are now unrelated).


`string_view` and `string` have value semantics. In other words:

string s = sv;
assert(s == sv);

They are not like pointers, where value is equivalent to the identity of
the underlying data. Two `string_view`s that internally reference the same
data are no more related than two `string`s of equal value. Equality is
what matters, not the underlying representation. The are no side effects.
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which may
discourage people from using it -- a net loss in my view. The usability of
a type should not be hamstrung because of a fear that users might not aware
of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing
an explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
Post by Nicol Bolas
And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them to
`std::string`s; they're for APIs where you don't need to modify the string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
People use C++ because they want performance. We should do what we can to
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many. Disallowing conversion from
`string_view` to `string` is not making the fast path the default; it is
disabling the default path because it has been deemed too slow. I have no
idea why this conversion has been singled out in this regard; consider the
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing. Why is one allowed and the
other isn't? This is inconsistent. It makes no sense.
As another example of how requiring *explicit* conversion in this case is
wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified. At some point in the future, the programmer switches to a new
version of the 3rd party library, which has updated its interfaces to
support `string_view`. To avoid breaking user code, extra overloads of
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
The problem here is that the explicit cast to `string` has suppressed the
type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to a topic in the
Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/a/is
ocpp.org/d/topic/std-discussion/YVGIEJOt_E0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Hodges
2017-03-23 16:16:06 UTC
Permalink
Post by Joseph Thomson
You are talking about commutativity
Thank you for the correction.
Post by Joseph Thomson
In our case, `string_view` and `string` are both conceptually "strings"
I respectfully disagree. A new string_view is more similar in concept to a
std::reference_wrapper<std::string> than it is to a std::string. Copying it
into another std::string_view creates two views of the same string. Almost
exactly like a pointer, but better. It is a pointer with guarantees and
behavioural constraints.

argument 1:
A new std::string is a brand new object which bears no relation to its
source. Modifying the source does not invalidate the new string. They are
completely separated. Modifying the source of a string_view invalidates the
string_view. It seems to me that one ought to be very sure of which of
these will happen when writing code.

argument 2:
Allowing std::string to be created from a string_view seems to me to be
equivalent to providing std::unique_ptr with a constructor that takes
(std::observer_ptr<T> observer), which then executes the following code:

unique_ptr(new T(*observer))

i.e. automatically dereferencing the pointer and calling a copy constructor
on the dereferenced value.

I think the c++ community would find this behaviour somewhat "surprising".
Post by Joseph Thomson
Post by j***@gmail.com
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
calls `frobnicate`, *he has to add an explicit conversion* to `string`
There seems to me to be a logical equivalence when creating a string_view
from a string. I.e. the string_view is a view of the string.
Creating a string from a string_view does not infer the same equivalence -
I think the correct term is that the operation is not associative. A.B is
not the same as B.A. This conversion actually constructs a new copy, not a
view or reference. It is a different kind of operation.
You are talking about commutativity. However, this concept can only be
applied to binary operations. A type conversion is not a binary operation;
it is a mapping.
If you want to establish a mathematical basis for type conversions, you
probably want to look at the concept of homomorphisms. A homomorphism is a
structure-preserving mapping between two algebraic structures of the same
type. For example, if you have a homomorphism, f : A -> B, that maps
structure A to structure B, it will preserve the operations. For example,
f(x + y) = f(x) + f(y)
If you apply this concept to the C++ type system, `A` and `B` are types
that meet the requirements of a shared concept, and the homomorphism `f` is
the conversion from `A` to `B`.
In our case, `string_view` and `string` are both conceptually "strings"
(they are the same kind of thing), and a conversion (homomorphism) does
exist from `string_view` to `string`, because the conversion maintains the
string operations (e.g. `length`, `substr`, `operator[]`, `operator+`). In
fact, a two-way conversion (isomorphism) between `string_view` and `string`
exists because `string` can also convert to `string_view` (which cannot be
said for other related pairs of types, like `int` and `short`).
Of course, exceptions throw a spanner in the works, because there is no
mathematical analogue (to my knowledge). I strongly believe that
conversions should be allowed to throw. This way, conversion can be allowed
for a partial mapping, f, where f(x) is undefined for some values of x (for
example, Robert Ramey's proposed Boost Safe Numerics library uses
exceptions like this to great effect, where for example, conversion from
`safe<long>` to `safe<short>` is permitted but may throw).
Conversion of value semantic types is a mathematical concept. Performance
concerns should not factor into the equation.
In my view, statement of intent of this copy should be explicit, as it has
side-effects. (i.e. the two objects are now unrelated).
string s = sv;
assert(s == sv);
They are not like pointers, where value is equivalent to the identity of
the underlying data. Two `string_view`s that internally reference the same
data are no more related than two `string`s of equal value. Equality is
what matters, not the underlying representation. The are no side effects.
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing
an explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
Post by Nicol Bolas
And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
People use C++ because they want performance. We should do what we can to
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many. Disallowing conversion from
`string_view` to `string` is not making the fast path the default; it is
disabling the default path because it has been deemed too slow. I have no
idea why this conversion has been singled out in this regard; consider the
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing. Why is one allowed and the
other isn't? This is inconsistent. It makes no sense.
As another example of how requiring *explicit* conversion in this case
is wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified. At some point in the future, the programmer switches to a new
version of the 3rd party library, which has updated its interfaces to
support `string_view`. To avoid breaking user code, extra overloads of
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
The problem here is that the explicit cast to `string` has suppressed
the type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to a topic in the
Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/a/is
ocpp.org/d/topic/std-discussion/YVGIEJOt_E0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-23 16:48:44 UTC
Permalink
Post by Joseph Thomson
You are talking about commutativity
Thank you for the correction.
Post by Joseph Thomson
In our case, `string_view` and `string` are both conceptually "strings"
I respectfully disagree.


I respectfully disagree too :)

A new string_view is more similar in concept to a
std::reference_wrapper<std::string> than it is to a std::string.


I have to point out, `reference_wrapper<string>` is convertible to `string`.

Copying it into another std::string_view creates two views of the same
string. Almost exactly like a pointer, but better. It is a pointer with
guarantees and behavioural constraints.


The key difference between `string_view` or `string const&` or
`reference_wrapper<string>`
and a pointer is how comparison behaves. A pointer has reference comparison
semantics (the identity of the referenced object is compared), while all
the other types have value comparison semantics (the value of the
referenced object is compared). This is a very important distinction.

argument 1:
A new std::string is a brand new object which bears no relation to its
source. Modifying the source does not invalidate the new string. They are
completely separated. Modifying the source of a string_view invalidates the
string_view. It seems to me that one ought to be very sure of which of
these will happen when writing code.


You have to be careful when working with references of any form in C++, and
`string_view` is no exception. And anyway, it could be argued that
forbidding conversion to `string` will only make it more likely that the
user will hold on to a dangling `string_view`. If you want to discourage
dangling `string_view`s, disable conversion from `string` to `string_view`
instead.


argument 2:
Allowing std::string to be created from a string_view seems to me to be
equivalent to providing std::unique_ptr with a constructor that takes
(std::observer_ptr<T> observer), which then executes the following code:

unique_ptr(new T(*observer))

i.e. automatically dereferencing the pointer and calling a copy constructor
on the dereferenced value.

I think the c++ community would find this behaviour somewhat "surprising".


Copying a pointer never results in a copy of the referenced object, which
is why this would be surprising. `string_view` is a reference-like type,
not a pointer-like type, as you pointed out, and copying a reference
results in a copy of the referenced object if the target object is not
itself reference-like. So that conversion from `string_view` to `string` be
enabled, and that it makes a copy of the referenced object, is not unusual
in this regard.
Post by Joseph Thomson
Post by j***@gmail.com
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
calls `frobnicate`, *he has to add an explicit conversion* to `string`
There seems to me to be a logical equivalence when creating a string_view
from a string. I.e. the string_view is a view of the string.
Creating a string from a string_view does not infer the same equivalence -
I think the correct term is that the operation is not associative. A.B is
not the same as B.A. This conversion actually constructs a new copy, not a
view or reference. It is a different kind of operation.
You are talking about commutativity. However, this concept can only be
applied to binary operations. A type conversion is not a binary operation;
it is a mapping.
If you want to establish a mathematical basis for type conversions, you
probably want to look at the concept of homomorphisms. A homomorphism is a
structure-preserving mapping between two algebraic structures of the same
type. For example, if you have a homomorphism, f : A -> B, that maps
structure A to structure B, it will preserve the operations. For example,
f(x + y) = f(x) + f(y)
If you apply this concept to the C++ type system, `A` and `B` are types
that meet the requirements of a shared concept, and the homomorphism `f` is
the conversion from `A` to `B`.
In our case, `string_view` and `string` are both conceptually "strings"
(they are the same kind of thing), and a conversion (homomorphism) does
exist from `string_view` to `string`, because the conversion maintains the
string operations (e.g. `length`, `substr`, `operator[]`, `operator+`). In
fact, a two-way conversion (isomorphism) between `string_view` and `string`
exists because `string` can also convert to `string_view` (which cannot be
said for other related pairs of types, like `int` and `short`).
Of course, exceptions throw a spanner in the works, because there is no
mathematical analogue (to my knowledge). I strongly believe that
conversions should be allowed to throw. This way, conversion can be allowed
for a partial mapping, f, where f(x) is undefined for some values of x (for
example, Robert Ramey's proposed Boost Safe Numerics library uses
exceptions like this to great effect, where for example, conversion from
`safe<long>` to `safe<short>` is permitted but may throw).
Conversion of value semantic types is a mathematical concept. Performance
concerns should not factor into the equation.
In my view, statement of intent of this copy should be explicit, as it has
side-effects. (i.e. the two objects are now unrelated).
string s = sv;
assert(s == sv);
They are not like pointers, where value is equivalent to the identity of
the underlying data. Two `string_view`s that internally reference the same
data are no more related than two `string`s of equal value. Equality is
what matters, not the underlying representation. The are no side effects.
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be aware
of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor of
`std::string` just because it doesn't implicitly convert to `std::string`
is a programmer who doesn't *deserve* to have `string_view`. Providing
an explicit conversion requires minimal effort on the caller's part; it is
hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
Post by Nicol Bolas
And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
People use C++ because they want performance. We should do what we can to
Post by Nicol Bolas
make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many. Disallowing conversion from
`string_view` to `string` is not making the fast path the default; it is
disabling the default path because it has been deemed too slow. I have no
idea why this conversion has been singled out in this regard; consider the
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing. Why is one allowed and the
other isn't? This is inconsistent. It makes no sense.
As another example of how requiring *explicit* conversion in this case
is wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified. At some point in the future, the programmer switches to a new
version of the 3rd party library, which has updated its interfaces to
support `string_view`. To avoid breaking user code, extra overloads of
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to a
`string` wherever he calls `frobnicate`, he experiences no performance
increase. If conversion from `string_view` to `string` *had* been
supported, this would not have been the case, and the performance of the
programmer's code would have returned to its pre-`string_view` state.
The problem here is that the explicit cast to `string` has suppressed
the type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to a topic in the
Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/a/is
ocpp.org/d/topic/std-discussion/YVGIEJOt_E0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to a topic in the
Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/a/
isocpp.org/d/topic/std-discussion/YVGIEJOt_E0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Richard Hodges
2017-03-23 17:20:06 UTC
Permalink
Post by Joseph Thomson
I respectfully disagree too :)
It seems we are at an ideological impasse.

I take on board your comments about the behaviour of construction from
references. They do muddy the waters of my argument.

I think I can summaries our divergent opinions in the following way - you
value convenience, and have the view that the wider community will too,
while I value the necessity of explicit expressions of logical intent.

I have to say that in any other language, I would probably take your
position too. Perhaps there is something about my perception of c++ (many
years of getting fingers burned in c perhaps?) that makes me lean towards
explicit expressions of intent - particularly when memory allocation and
object conversion/copying is concerned.

Perhaps there is an ideological case to explore whether construction from
references should be deprecated in favour of construction from
copy_wrappers - consider:

auto x = move(y); // definitely a move

auto p = copy(q); // definitely a copy

a = a_type { copy(b), move(c) }; // definitely copied and moved

auto r = s; // illegal for non-arithmetic types

... but then maybe this is the first step on the road to COBOL++
Post by Joseph Thomson
Post by Joseph Thomson
You are talking about commutativity
Thank you for the correction.
Post by Joseph Thomson
In our case, `string_view` and `string` are both conceptually "strings"
I respectfully disagree.
I respectfully disagree too :)
A new string_view is more similar in concept to a
std::reference_wrapper<std::string> than it is to a std::string.
I have to point out, `reference_wrapper<string>` is convertible to `string`.
Copying it into another std::string_view creates two views of the same
string. Almost exactly like a pointer, but better. It is a pointer with
guarantees and behavioural constraints.
The key difference between `string_view` or `string const&` or `reference_wrapper<string>`
and a pointer is how comparison behaves. A pointer has reference comparison
semantics (the identity of the referenced object is compared), while all
the other types have value comparison semantics (the value of the
referenced object is compared). This is a very important distinction.
A new std::string is a brand new object which bears no relation to its
source. Modifying the source does not invalidate the new string. They are
completely separated. Modifying the source of a string_view invalidates the
string_view. It seems to me that one ought to be very sure of which of
these will happen when writing code.
You have to be careful when working with references of any form in C++,
and `string_view` is no exception. And anyway, it could be argued that
forbidding conversion to `string` will only make it more likely that the
user will hold on to a dangling `string_view`. If you want to discourage
dangling `string_view`s, disable conversion from `string` to `string_view`
instead.
Allowing std::string to be created from a string_view seems to me to be
equivalent to providing std::unique_ptr with a constructor that takes
unique_ptr(new T(*observer))
i.e. automatically dereferencing the pointer and calling a copy
constructor on the dereferenced value.
I think the c++ community would find this behaviour somewhat "surprising".
Copying a pointer never results in a copy of the referenced object, which
is why this would be surprising. `string_view` is a reference-like type,
not a pointer-like type, as you pointed out, and copying a reference
results in a copy of the referenced object if the target object is not
itself reference-like. So that conversion from `string_view` to `string` be
enabled, and that it makes a copy of the referenced object, is not unusual
in this regard.
Post by Joseph Thomson
Post by j***@gmail.com
The programmer decides to start using `string_view` throughout his
code base. Because `string_view` doesn't convert to `string`, wherever
he calls `frobnicate`, *he has to add an explicit conversion* to `string`
There seems to me to be a logical equivalence when creating a string_view
from a string. I.e. the string_view is a view of the string.
Creating a string from a string_view does not infer the same equivalence
- I think the correct term is that the operation is not associative. A.B is
not the same as B.A. This conversion actually constructs a new copy, not a
view or reference. It is a different kind of operation.
You are talking about commutativity. However, this concept can only be
applied to binary operations. A type conversion is not a binary operation;
it is a mapping.
If you want to establish a mathematical basis for type conversions, you
probably want to look at the concept of homomorphisms. A homomorphism is a
structure-preserving mapping between two algebraic structures of the same
type. For example, if you have a homomorphism, f : A -> B, that maps
structure A to structure B, it will preserve the operations. For example,
f(x + y) = f(x) + f(y)
If you apply this concept to the C++ type system, `A` and `B` are types
that meet the requirements of a shared concept, and the homomorphism `f` is
the conversion from `A` to `B`.
In our case, `string_view` and `string` are both conceptually "strings"
(they are the same kind of thing), and a conversion (homomorphism) does
exist from `string_view` to `string`, because the conversion maintains the
string operations (e.g. `length`, `substr`, `operator[]`, `operator+`). In
fact, a two-way conversion (isomorphism) between `string_view` and `string`
exists because `string` can also convert to `string_view` (which cannot be
said for other related pairs of types, like `int` and `short`).
Of course, exceptions throw a spanner in the works, because there is no
mathematical analogue (to my knowledge). I strongly believe that
conversions should be allowed to throw. This way, conversion can be allowed
for a partial mapping, f, where f(x) is undefined for some values of x (for
example, Robert Ramey's proposed Boost Safe Numerics library uses
exceptions like this to great effect, where for example, conversion from
`safe<long>` to `safe<short>` is permitted but may throw).
Conversion of value semantic types is a mathematical concept. Performance
concerns should not factor into the equation.
In my view, statement of intent of this copy should be explicit, as it
has side-effects. (i.e. the two objects are now unrelated).
string s = sv;
assert(s == sv);
They are not like pointers, where value is equivalent to the identity of
the underlying data. Two `string_view`s that internally reference the same
data are no more related than two `string`s of equal value. Equality is
what matters, not the underlying representation. The are no side effects.
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
In my opinion, it the responsibility of the owner an object to be
aware of when potentially expensive copies are being made. The distinction
between implicit and explicit conversion should be made on the basis of
safety and correctness, not performance. Disallowing conversion from
`string_view` to `string` makes `string_view` awkward to use, which
may discourage people from using it -- a net loss in my view. The usability
of a type should not be hamstrung because of a fear that users might not
aware of the performance costs of certain operations.
A programmer who would genuinely give up using `string_view` in favor
of `std::string` just because it doesn't implicitly convert to
`std::string` is a programmer who doesn't *deserve* to have
`string_view`. Providing an explicit conversion requires minimal effort on
the caller's part; it is hardly sufficient reason to stop using a class.
This is typical "expert" mentality. Whether your users are the general
public or other programmers, if your product violates their expectations,
they will be reluctant to use it. Ignore your users at your own peril.
Post by Nicol Bolas
And furthermore, if you have so many conversions from `string_view` to
`std::string` that you encounter this problem frequently, you're using
`string_view` wrong. You aren't *supposed* to frequently convert them
to `std::string`s; they're for APIs where you don't need to modify the
string.
Or maybe the user simply has requirements that do not align with your
expectations. I don't presume to know user requirements.
People use C++ because they want performance. We should do what we can
Post by Nicol Bolas
to make it hard for people to accidentally do slow things. The fast path
should be the default wherever possible, and to discourage the slow path,
we should
Performance is just one concern of many. Disallowing conversion from
`string_view` to `string` is not making the fast path the default; it
is disabling the default path because it has been deemed too slow. I have
no idea why this conversion has been singled out in this regard; consider
string s;
string_view sv = s;
string s1 = s; // okay
string s2 = sv; // error
These operations do the *same* exact thing. Why is one allowed and the
other isn't? This is inconsistent. It makes no sense.
As another example of how requiring *explicit* conversion in this case
is wrong, consider a programmer who is using a 3rd party library with the
void frobnicate(std::string const& s);
The programmer decides to start using `string_view` throughout his code
base. Because `string_view` doesn't convert to `string`, wherever he
frobnicate(std::string(sv))
Unfortunately, this does have an impact on the performance of the user's
code. However, this cannot be helped because the 3rd party library cannot
be modified. At some point in the future, the programmer switches to a new
version of the 3rd party library, which has updated its interfaces to
support `string_view`. To avoid breaking user code, extra overloads of
void frobnicate(std::string const&);
void frobnicate(std::string_view);
void frobnicate(char const*);
Unfortunately, because the programmer is casting each `string_view` to
a `string` wherever he calls `frobnicate`, he experiences no
performance increase. If conversion from `string_view` to `string` *had*
been supported, this would not have been the case, and the performance of
the programmer's code would have returned to its pre-`string_view`
state.
The problem here is that the explicit cast to `string` has suppressed
the type system, which has disabled the overload resolution mechanism which
would otherwise have chosen the most appropriate function to call. As I
said previously, if a conversion is correct and safe, it should be
implicit. Performance should *not* be a consideration.
--
---
You received this message because you are subscribed to the Google
Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to a topic in the
Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/a/is
ocpp.org/d/topic/std-discussion/YVGIEJOt_E0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to a topic in the
Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/a/is
ocpp.org/d/topic/std-discussion/YVGIEJOt_E0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
Visit this group at https://groups.google.com/a/is
ocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 02:14:08 UTC
Permalink
Post by Richard Hodges
Post by Joseph Thomson
I respectfully disagree too :)
It seems we are at an ideological impasse.
I take on board your comments about the behaviour of construction from
references. They do muddy the waters of my argument.
I think I can summaries our divergent opinions in the following way - you
value convenience, and have the view that the wider community will too,
while I value the necessity of explicit expressions of logical intent.
I value convenience, but I value correctness and consistency more. It just
happens that convenience often results from applying correct and consistent
design principles. Efficiency also tends to result from applying correct
and consistent design principles. The concern about efficiency of
conversion from `string_view` to `string` is misplaced. I have already
demonstrated how requiring explicit invocation of the `string` constructor
encourages suppression of the type system and interferes with overload
resolution, resulting in sub-optimal performance if the programmer is not
very careful. But this is by no means the biggest problem...

To demonstrate how the this decision to disable the conversion can go way
beyond the inconvenience (and potential inadvertent performance impact) of
having to write `std::string(sv)` every now and then, let me re-state the
problem that originally inspired me to think about this. Consider using a
`string_view` as a key in a `map<string, X, less<>>`. Heterogeneous keys
are already supported for observers:

auto it = m.find(sv); // okay, because `string` converts to `string_view`

But heterogeneous keys are not supported for modifiers:

m[sv] = v; // error: no `operator[](std::string_view)`

In this case, converting to `string` can be very inefficient, especially
inside a loop:

m[std::string(sv)] = v; // `string` constructed even if entry exists

We could modify `map` to support heterogeneous keys in this case with the
requirement that the key type be convertible to `map::key_type`:

template <typename K, typename = enable_if_t<is_convertible_v<K, key_type>>>
T& map::operator[](K const& key);

But we still cannot use `string_view` because it is not convertible to
`string`. Instead, we are forced to essentially re-implement `operator[]`
just to get optimal efficiency:

auto it = m.lower_bound(sv);
if (it == m.end() || std::less<>()(sv, it->first)) {
it = m.emplace_hint(it, sv, v);
} else {
it->second = v;
}

Is it reasonable to expect the average user to do this just to get good
performance? And I'm sure there will be other places where inability to
convert `string_view` to `string` will have a knock-on effect.

Of course, you could weaken the requirement for `operator[]` to
`is_constructible_v<key_type, K>`, but would be letting the poor design
choices for `string_view` influence poor design choices (weakened type
safety) for `map`. This is the result of not consistently following correct
design principles.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-24 03:48:25 UTC
Permalink
Post by j***@gmail.com
Post by Richard Hodges
Post by Joseph Thomson
I respectfully disagree too :)
It seems we are at an ideological impasse.
I take on board your comments about the behaviour of construction from
references. They do muddy the waters of my argument.
I think I can summaries our divergent opinions in the following way - you
value convenience, and have the view that the wider community will too,
while I value the necessity of explicit expressions of logical intent.
I value convenience, but I value correctness and consistency more. It just
happens that convenience often results from applying correct and consistent
design principles. Efficiency also tends to result from applying correct
and consistent design principles. The concern about efficiency of
conversion from `string_view` to `string` is misplaced. I have already
demonstrated how requiring explicit invocation of the `string` constructor
encourages suppression of the type system and interferes with overload
resolution, resulting in sub-optimal performance if the programmer is not
very careful. But this is by no means the biggest problem...
To demonstrate how the this decision to disable the conversion can go way
beyond the inconvenience (and potential inadvertent performance impact) of
having to write `std::string(sv)` every now and then, let me re-state the
problem that originally inspired me to think about this. Consider using a
`string_view` as a key in a `map<string, X, less<>>`. Heterogeneous keys
auto it = m.find(sv); // okay, because `string` converts to `string_view`
m[sv] = v; // error: no `operator[](std::string_view)`
In this case, converting to `string` can be very inefficient, especially
m[std::string(sv)] = v; // `string` constructed even if entry exists
We could modify `map` to support heterogeneous keys in this case with the
template <typename K, typename = enable_if_t<is_convertible_v<K, key_type
T& map::operator[](K const& key);
But we still cannot use `string_view` because it is not convertible to
`string`. Instead, we are forced to essentially re-implement `operator[]`
Or you could choose `is_constructible` rather than `is_convertible`. After
all, the user's clear intent is to use `K` to create a `key_type` if that
is necessary. The user would otherwise have done `map_obj[key_type(k)]` to
access the value. You're simply providing a potentially more optimal form
of that.

The question you have for heterogeneous maps is this: is it reasonable to
assume that two types which are comparable are also implicitly convertible?
I think there's a decent argument to be made either way.

Or even better, since this feature can't be used unless the comparison has
the heterogeneous flag, you could also allow the comparison object itself
to do the conversion from `K` to `key_type`. That allows the comparison
object to handle various cases where you don't want implicit conversions,
but you do want conversions for this particular use of `map`.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 07:23:29 UTC
Permalink
Post by Nicol Bolas
Post by j***@gmail.com
Post by Richard Hodges
Post by Joseph Thomson
I respectfully disagree too :)
It seems we are at an ideological impasse.
I take on board your comments about the behaviour of construction from
references. They do muddy the waters of my argument.
I think I can summaries our divergent opinions in the following way -
you value convenience, and have the view that the wider community will too,
while I value the necessity of explicit expressions of logical intent.
I value convenience, but I value correctness and consistency more. It
just happens that convenience often results from applying correct and
consistent design principles. Efficiency also tends to result from applying
correct and consistent design principles. The concern about efficiency of
conversion from `string_view` to `string` is misplaced. I have already
demonstrated how requiring explicit invocation of the `string` constructor
encourages suppression of the type system and interferes with overload
resolution, resulting in sub-optimal performance if the programmer is not
very careful. But this is by no means the biggest problem...
To demonstrate how the this decision to disable the conversion can go way
beyond the inconvenience (and potential inadvertent performance impact) of
having to write `std::string(sv)` every now and then, let me re-state the
problem that originally inspired me to think about this. Consider using a
`string_view` as a key in a `map<string, X, less<>>`. Heterogeneous keys
auto it = m.find(sv); // okay, because `string` converts to `string_view`
m[sv] = v; // error: no `operator[](std::string_view)`
In this case, converting to `string` can be very inefficient, especially
m[std::string(sv)] = v; // `string` constructed even if entry exists
We could modify `map` to support heterogeneous keys in this case with the
template <typename K, typename = enable_if_t<is_convertible_v<K, key_type
T& map::operator[](K const& key);
But we still cannot use `string_view` because it is not convertible to
`string`. Instead, we are forced to essentially re-implement `operator[]`
Or you could choose `is_constructible` rather than `is_convertible`. After
all, the user's clear intent is to use `K` to create a `key_type` if that
is necessary. The user would otherwise have done `map_obj[key_type(k)]` to
access the value. You're simply providing a potentially more optimal form
of that.
This is fine for `string_view`, because creating a `string` from a
`string_view` is safe (which is why conversion *should* be supported). This
is not always the case. Consider a integral wrapper type `safer<T>`, which
makes narrowing conversions explicit:

safer<long> a = 100000;
safer<short> b = a; // error (narrowing conversion)

map<safer<short>, string> m;
m[a] = "hello, world"; // okay (oops)

The question you have for heterogeneous maps is this: is it reasonable to
Post by Nicol Bolas
assume that two types which are comparable are also implicitly convertible?
I think there's a decent argument to be made either way.
As in the above example, conversion need only be supported in one direction
(homomorphism) to imply comparability. Conversion in both directions
(isomorphism) may be supported, but it isn't necessary. In other words, two
types are comparable if conversion is supported in at least one direction.
Post by Nicol Bolas
Or even better, since this feature can't be used unless the comparison has
the heterogeneous flag, you could also allow the comparison object itself
to do the conversion from `K` to `key_type`. That allows the comparison
object to handle various cases where you don't want implicit conversions,
but you do want conversions for this particular use of `map`.
I'm not sure what you mean here. The comparison object shouldn't do any
explicit conversion. Conversion is only required because a copy of the key
might be stored.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 12:47:20 UTC
Permalink
I've just realised that assignment of `string_view` to `string` is
defined... what??

string_view sv;
string s = sv; // error
s = sv; // a-okay...

If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?! This
is totally inconsistent.

I'm probably just going to go ahead and file a defect report.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Olaf van der Spek
2017-03-24 13:22:57 UTC
Permalink
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?!
This is totally inconsistent.
I'm probably just going to go ahead and file a defect report.
string s = sv not being allowed is an unfortunate side-effect, it's (AFAIK)
not the reason for the explicit constructor from string_view.

void f(const string& s);

Isn't the real problem this construct allowing implicit conversion?
What if, like non-const&, const& in general didn't allow such conversions?

Maybe explicit is too overloaded.. ;)
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Matthew Woehlke
2017-03-24 13:57:35 UTC
Permalink
Post by Olaf van der Spek
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?!
This is totally inconsistent.
string s = sv not being allowed is an unfortunate side-effect, it's (AFAIK)
not the reason for the explicit constructor from string_view.
void f(const string& s);
As I said elsewhere:

void f(const string& s);

f("hello, world!"); // okay

string_view sv = "hello, world!";
f(sv); // error?!

Yes, I hear you saying "in a perfect world neither of those would be
okay". Well, I'm unconvinced that all the rampant inconsistency is worth
the theoretical performance advantage, especially since Joseph showed a
case where the lack of conversion leads to explicit construction, which
later becomes a pessimization itself.

This:

void f(const string&); // legacy
void f(string_view);

string_view sv = ...;
f(string(sv)); // string_view overload didn't exist when written

...is unacceptable IMHO. We either need a way, *now*, for compilers to
diagnose this, or we need to not cause it in the first place.
--
Matthew
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-03-24 13:30:51 UTC
Permalink
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?! This
is totally inconsistent.
I disagree that this implies that the design is "totally"
inconsistent, construction is a different thing than assignment. In
particular, assignability would never be considered during
construction (But vice versa), so the result of std::is_convertible is
never weakened by the existence of a assignment operator. This is
similar for std::regex: There is an *explicit* constructor from char
pointer (and one from basic_string):

explicit basic_regex(const charT* p, flag_type f = regex_constants::ECMAScript);

but there is also an assignment operator from char pointer (and one
from basic_string):

basic_regex& operator=(const charT* ptr);

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-24 14:59:52 UTC
Permalink
Post by Daniel Krügler
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?!
This
Post by j***@gmail.com
is totally inconsistent.
I disagree that this implies that the design is "totally"
inconsistent, construction is a different thing than assignment. In
particular, assignability would never be considered during
construction (But vice versa), so the result of std::is_convertible is
never weakened by the existence of a assignment operator.
I'm not saying it's the same operation. But assignment *is* an implicit
operation. If you enable conversion, you get assignment by default:

struct foo {
foo(int);
};

foo a = 42;
a = 42; // equivalent to `a = foo(42)`

If you disable conversion, you disable assignment:

struct foo {
explicit foo(int);
};

foo a = 42; // error
a = 42; // error

You have to explicitly enable assignment if you want to allow it again:

struct foo {
explicit foo(int);
foo& operator=(int);
};

foo a = 42; // error
a = 42; // okay

Overloading `operator=` is great for efficiency, to avoid constructing an
additional temporary, but enabling it when conversion is disabled is a
strange use of the type system that is not appropriate when dealing with
regular types. `string` is regular. `string_view` is regular. But `string`
and `string_view` do not interoperate in a regular fashion.

This is
Post by Daniel Krügler
similar for std::regex: There is an *explicit* constructor from char
explicit basic_regex(const charT* p, flag_type f =
regex_constants::ECMAScript);
but there is also an assignment operator from char pointer (and one
basic_regex& operator=(const charT* ptr);
`basic_regex` is not a regular type. Even so, use of `operator=` in this
way could be considered odd in the same way that some consider overloading
`operator<<` for stream objects odd. Personally, I think
`basic_regex::assign` alone would have sufficed.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-24 13:34:36 UTC
Permalink
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?! This
is totally inconsistent.
I'm probably just going to go ahead and file a defect report.
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-24 13:45:24 UTC
Permalink
On Fri, Mar 24, 2017 at 9:34 PM, Ville Voutilainen <
Post by Ville Voutilainen
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of `string_view`,
then why on earth is assignment of `string_view` to `string` allowed?!
This
Post by j***@gmail.com
is totally inconsistent.
I'm probably just going to go ahead and file a defect report.
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
Thanks. Even if it isn't a defect, I worry that it is a decision (mistake
in my opinion) that may be irreversible because of user code breakage.
Could you provide any insight into the rationale behind the decision? It
would be of great help if I am going to make a case against it.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-24 13:47:09 UTC
Permalink
Post by Ville Voutilainen
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
Thanks. Even if it isn't a defect, I worry that it is a decision (mistake in
my opinion) that may be irreversible because of user code breakage. Could
you provide any insight into the rationale behind the decision? It would be
of great help if I am going to make a case against it.
The rationale is that the conversion allocates memory, so it shouldn't
happen silently
in function calls.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-24 13:48:35 UTC
Permalink
On Fri, Mar 24, 2017 at 9:47 PM, Ville Voutilainen <
Post by Joseph Thomson
Post by Ville Voutilainen
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
Thanks. Even if it isn't a defect, I worry that it is a decision
(mistake in
Post by Joseph Thomson
my opinion) that may be irreversible because of user code breakage. Could
you provide any insight into the rationale behind the decision? It would
be
Post by Joseph Thomson
of great help if I am going to make a case against it.
The rationale is that the conversion allocates memory, so it shouldn't
happen silently
in function calls.
Thanks for confirming this.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Olaf van der Spek
2017-03-24 13:50:56 UTC
Permalink
Post by Ville Voutilainen
Post by Ville Voutilainen
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
Thanks. Even if it isn't a defect, I worry that it is a decision (mistake in
my opinion) that may be irreversible because of user code breakage. Could
you provide any insight into the rationale behind the decision? It would be
of great help if I am going to make a case against it.
The rationale is that the conversion allocates memory, so it shouldn't
happen silently
in function calls.
Right, so what's the plan for f("X") when the type is const string&?
--
Olaf
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-24 14:00:12 UTC
Permalink
Post by Olaf van der Spek
Post by Ville Voutilainen
The rationale is that the conversion allocates memory, so it shouldn't
happen silently
in function calls.
Right, so what's the plan for f("X") when the type is const string&?
There is no plan to change it.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Olaf van der Spek
2017-03-24 14:09:55 UTC
Permalink
Post by Ville Voutilainen
Post by Olaf van der Spek
Post by Ville Voutilainen
The rationale is that the conversion allocates memory, so it shouldn't
happen silently
in function calls.
Right, so what's the plan for f("X") when the type is const string&?
There is no plan to change it.
It's still 'bad' isn't it?
Do compilers warn for it? Do code analyzers?

I don't entirely get the discrepancy between const char* and string_view here.
--
Olaf
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-24 14:18:36 UTC
Permalink
Post by Olaf van der Spek
Post by Ville Voutilainen
Post by Olaf van der Spek
Right, so what's the plan for f("X") when the type is const string&?
There is no plan to change it.
It's still 'bad' isn't it?
Is it? If the literal is short, there's no allocation since it fits
into an SSO string.
Post by Olaf van der Spek
Do compilers warn for it? Do code analyzers?
I doubt compilers warn about it since that would generate fair amounts
of false positives.
I am unaware of any special warning flags that would warn on it, and I
have no idea whether
analyzers diagnose it.
Post by Olaf van der Spek
I don't entirely get the discrepancy between const char* and string_view here.
The one we can't change for compatibility reasons, the other we can.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Olaf van der Spek
2017-03-24 14:23:53 UTC
Permalink
Post by Ville Voutilainen
Post by Olaf van der Spek
Post by Ville Voutilainen
Post by Olaf van der Spek
Right, so what's the plan for f("X") when the type is const string&?
There is no plan to change it.
It's still 'bad' isn't it?
Is it? If the literal is short, there's no allocation since it fits
into an SSO string.
If it's a literal you'd think the compiler could construct it at compile-time.
But it could be a const char* too..

BTW, SSO works for string_view too.
Post by Ville Voutilainen
Post by Olaf van der Spek
Do compilers warn for it? Do code analyzers?
I doubt compilers warn about it since that would generate fair amounts
of false positives.
I am unaware of any special warning flags that would warn on it, and I
have no idea whether
analyzers diagnose it.
Post by Olaf van der Spek
I don't entirely get the discrepancy between const char* and string_view here.
The one we can't change for compatibility reasons, the other we can.
I'm not sure there's nothing that can be done. Deprecation is one
thing that comes to mind, (optional) compiler warnings are another.
--
Olaf
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-24 14:33:05 UTC
Permalink
Post by Olaf van der Spek
Post by Ville Voutilainen
Post by Olaf van der Spek
I don't entirely get the discrepancy between const char* and string_view here.
The one we can't change for compatibility reasons, the other we can.
I'm not sure there's nothing that can be done. Deprecation is one
thing that comes to mind, (optional) compiler warnings are another.
That is, as they say, your time to waste.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-24 14:45:18 UTC
Permalink
On Fri, Mar 24, 2017 at 10:33 PM, Ville Voutilainen <
Post by Olaf van der Spek
Post by Olaf van der Spek
Post by Ville Voutilainen
Post by Olaf van der Spek
I don't entirely get the discrepancy between const char* and
string_view here.
Post by Olaf van der Spek
Post by Ville Voutilainen
The one we can't change for compatibility reasons, the other we can.
I'm not sure there's nothing that can be done. Deprecation is one
thing that comes to mind, (optional) compiler warnings are another.
That is, as they say, your time to waste.
The C++ Core Guidelines and GSL aim to address the issue of conversion from
`char const*` to `string` with `gsl::zstring`:

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f25-use-a-zstring-or-a-not_nullzstring-to-designate-a-c-style-string

String literals are fine, and obviously I don't agree that their implicit
conversion to `string` is incorrect.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-30 07:21:42 UTC
Permalink
Post by Nicol Bolas
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of
`string_view`,
Post by j***@gmail.com
then why on earth is assignment of `string_view` to `string` allowed?!
This
Post by j***@gmail.com
is totally inconsistent.
I'm probably just going to go ahead and file a defect report.
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
Dear all,

I have attached the first draft of a paper making the case for conversion
of `string_view` to `string` for your viewing. Obviously, I welcome any
feedback or thoughts people may have.

Thanks.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-30 07:44:10 UTC
Permalink
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
I've just realised that assignment of `string_view` to `string` is
defined... what??
string_view sv;
string s = sv; // error
s = sv; // a-okay...
If conversion from `string_view` to `string` is disabled because it
shouldn't be possible to implicitly perform deep copies of
`string_view`,
Post by j***@gmail.com
then why on earth is assignment of `string_view` to `string` allowed?!
This
Post by j***@gmail.com
is totally inconsistent.
I'm probably just going to go ahead and file a defect report.
The explicit conversion from string_view to string is not a defect,
it's intentional.
Write a paper.
Dear all,
I have attached the first draft of a paper making the case for conversion
of `string_view` to `string` for your viewing. Obviously, I welcome any
feedback or thoughts people may have.
Thanks.
I spotted some of potentially confusing typos in the first draft. Here is
the amended version.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Ville Voutilainen
2017-03-30 08:34:06 UTC
Permalink
Post by j***@gmail.com
Post by j***@gmail.com
Dear all,
I have attached the first draft of a paper making the case for conversion
of `string_view` to `string` for your viewing. Obviously, I welcome any
feedback or thoughts people may have.
Thanks.
I spotted some of potentially confusing typos in the first draft. Here is
the amended version.
Question:

string name = wgt.get_name(); // error


Why is this a problem? Using direct-initialization will make it work:

string name{wgt.get_name()}; // ok
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Olaf van der Spek
2017-03-30 08:58:04 UTC
Permalink
Post by Ville Voutilainen
Post by j***@gmail.com
Post by j***@gmail.com
Dear all,
I have attached the first draft of a paper making the case for conversion
of `string_view` to `string` for your viewing. Obviously, I welcome any
feedback or thoughts people may have.
Thanks.
I spotted some of potentially confusing typos in the first draft. Here is
the amended version.
string name = wgt.get_name(); // error
string name{wgt.get_name()}; // ok
There's no direct / good reason for the former to not work. It's a
consequence of explicit being required on the constructor for other
reasons.
--
Olaf
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-30 09:32:58 UTC
Permalink
Post by Ville Voutilainen
Post by j***@gmail.com
Post by j***@gmail.com
Dear all,
I have attached the first draft of a paper making the case for conversion
of `string_view` to `string` for your viewing. Obviously, I welcome any
feedback or thoughts people may have.
Thanks.
I spotted some of potentially confusing typos in the first draft. Here is
the amended version.
string name = wgt.get_name(); // error
string name{wgt.get_name()}; // ok
There's no direct / good reason for the former to not work. It's a
consequence of explicit being required on the constructor for other
reasons.


Exactly. Using `string_view` as a function parameter is fine because
`string` implicitly converts to `string_view`. Calling syntax is the same
as if it took `string const&`. Using `string_view` as a return type means
that the calling syntax is different in some cases (when converting to
`string`). Either you need to use direct initialization or do this:

string s;
s = wgt.get_name();

On its own, I don't think this issue would be reason enough to argue for
implicit conversion, and I certainly don't think my case depends on it. I
do think it makes my case slightly stronger though, so it's worth
mentioning.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-04-02 09:38:16 UTC
Permalink
Here is an interesting case of `string` and `string_view` interacting with
`variant` that I think is pertinent to the discussion.

struct str {
str() = default;
str(string_view) {}
str& operator=(string_view) = delete;
};

variant<string, str> s;
s = string_view();

cout << s.index() << "\n"; // prints `1` (i.e. `str`)

This potentially surprising behaviour seems to be because
`variant::operator=` assumes that types that support assignment from `T`
will also be convertible from `T` (it uses overload resolution as a guide
to picking the target type), so it picks `str` as the target type despite
it not being assignable from `string_view`. Note that deleting
`str::operator=(string_view)` *does* actually disable
`variant::operator=(string_view)`, but the assignment still works since the
`variant` is still copy constructible *and* convertible from `string_view`.
Presumably this is because `variant` assumes that a type that are *not*
assignable from `T` will not be convertible from `T` *either*.

These seem like two separate issues that both stem from the assumption that
conversion and assignment are either *both* supported or *neither* of them
are. At any rate, if `string` were convertible from `string_view`,
assignment of the `variant` would be always disabled, since `str` is also
convertible from `string_view`. This would meet the expectations of
`variant` and thereby avoid any potentially surprising behaviour.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-30 09:05:16 UTC
Permalink
Post by j***@gmail.com
Post by j***@gmail.com
Dear all,
I have attached the first draft of a paper making the case for conversion
of `string_view` to `string` for your viewing. Obviously, I welcome any
feedback or thoughts people may have.
Thanks.
I spotted some of potentially confusing typos in the first draft. Here is
the amended version.
Question:

string name = wgt.get_name(); // error


Why is this a problem? Using direct-initialization will make it work:

string name{wgt.get_name()}; // ok


First, it's a syntactic inconsistency. This is significant because it might
affect the decision of the authors of `widget` to use `string_view` (as I
mentioned, perhaps this means their priorities are wrong, but I'm sure it
will be an issue for some people).

Secondly, direct initialization can cause explicit conversion (which is why
you used it here). Thus, it is less safe in general. In this example, it is
probably a non-issue, but it could be an issue in generic code (e.g. if
`get_name` didn't always return `string_view`).

This is probably the least important issue of the lot, so I don't want to
let it distract from the others.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-24 15:04:29 UTC
Permalink
Post by j***@gmail.com
Post by Nicol Bolas
Post by j***@gmail.com
Post by Richard Hodges
Post by Joseph Thomson
I respectfully disagree too :)
It seems we are at an ideological impasse.
I take on board your comments about the behaviour of construction from
references. They do muddy the waters of my argument.
I think I can summaries our divergent opinions in the following way -
you value convenience, and have the view that the wider community will too,
while I value the necessity of explicit expressions of logical intent.
I value convenience, but I value correctness and consistency more. It
just happens that convenience often results from applying correct and
consistent design principles. Efficiency also tends to result from applying
correct and consistent design principles. The concern about efficiency of
conversion from `string_view` to `string` is misplaced. I have already
demonstrated how requiring explicit invocation of the `string` constructor
encourages suppression of the type system and interferes with overload
resolution, resulting in sub-optimal performance if the programmer is not
very careful. But this is by no means the biggest problem...
To demonstrate how the this decision to disable the conversion can go
way beyond the inconvenience (and potential inadvertent performance impact)
of having to write `std::string(sv)` every now and then, let me re-state
the problem that originally inspired me to think about this. Consider using
a `string_view` as a key in a `map<string, X, less<>>`. Heterogeneous keys
auto it = m.find(sv); // okay, because `string` converts to
`string_view`
m[sv] = v; // error: no `operator[](std::string_view)`
In this case, converting to `string` can be very inefficient, especially
m[std::string(sv)] = v; // `string` constructed even if entry exists
We could modify `map` to support heterogeneous keys in this case with
template <typename K, typename = enable_if_t<is_convertible_v<K, key_type>>>
T& map::operator[](K const& key);
But we still cannot use `string_view` because it is not convertible to
`string`. Instead, we are forced to essentially re-implement `operator[]`
Or you could choose `is_constructible` rather than `is_convertible`.
After all, the user's clear intent is to use `K` to create a `key_type` if
that is necessary. The user would otherwise have done
`map_obj[key_type(k)]` to access the value. You're simply providing a
potentially more optimal form of that.
This is fine for `string_view`, because creating a `string` from a
`string_view` is safe (which is why conversion *should* be supported).
This is not always the case. Consider a integral wrapper type `safer<T>`,
safer<long> a = 100000;
safer<short> b = a; // error (narrowing conversion)
map<safer<short>, string> m;
m[a] = "hello, world"; // okay (oops)
The question you have for heterogeneous maps is this: is it reasonable to
Post by Nicol Bolas
assume that two types which are comparable are also implicitly convertible?
I think there's a decent argument to be made either way.
As in the above example, conversion need only be supported in one
direction (homomorphism) to imply comparability. Conversion in both
directions (isomorphism) may be supported, but it isn't necessary. In other
words, two types are comparable if conversion is supported in at least one
direction.
The thing that allows `map<string, T, less<>>` to use `string_view` with
`find` is *not* the fact that `string_view` has an `operator<` with
`string`. It is the fact that `less<>` has an `operator()` that can take
both `string` and `string_view` (or more generally, anything). Even if
`string_view` itself had no `operator<` for `string`, you could create a
comparison type that provides one.

So the comparison type can manufacture comparison where none would
otherwise exist. So if we decide that comparison as a concept implies
implicit conversion, it also makes sense to allow the comparison type to
manufacture *conversion* where none would otherwise exist.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Vicente J. Botet Escriba
2017-03-23 22:06:57 UTC
Permalink
Post by Richard Hodges
Post by Joseph Thomson
You are talking about commutativity
Thank you for the correction.
Post by Joseph Thomson
In our case, `string_view` and `string` are both conceptually
"strings"
I respectfully disagree.
I respectfully disagree too :)
A new string_view is more similar in concept to a
std::reference_wrapper<std::string> than it is to a std::string.
I have to point out, `reference_wrapper<string>` is convertible to `string`.
No. It is convertible to T&

operator T& () const;

Vicente
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-23 23:44:21 UTC
Permalink
Post by Richard Hodges
Post by Joseph Thomson
You are talking about commutativity
Thank you for the correction.
Post by Joseph Thomson
In our case, `string_view` and `string` are both conceptually "strings"
I respectfully disagree.
I respectfully disagree too :)
A new string_view is more similar in concept to a
std::reference_wrapper<std::string> than it is to a std::string.
I have to point out, `reference_wrapper<string>` is convertible to `string`.
No. It is convertible to T&
operator T& () const;
Vicente
static_assert(is_convertible_v<reference_wrapper<string>, string>);
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
TONGARI J
2017-03-15 02:19:27 UTC
Permalink
Post by Tony V E
Post by TONGARI J
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm
working on that.
https://github.com/tvaneerd/isocpp/blob/master/conversions.md
In addition to 'not cheap', the constructor could throw. ‎Throwing from
'unseen' code is (somewhat) harder to deal with.
Well, copy ctor may throw as well...I really don't see a point here. I
don't think throw-ness or cheapness is a good criteria for explicit-ness.
It's better to judge by semantic.
By what semantic? That type two types represent the "same thing", or
something else?
A unary ctor is either for conversion or construction.
Conversion is typically for types in the same category, and construction is
typically for orthogonal types.
And for conversion, if the conversion does not lose information in the
type's domain, it should be implicit.

For example, consider a graphics library:

graphic::path path = graphic::ellipse(center, r);

A graphic::path is a container (would require heap allocation), and a
graphic::ellipse describes an ellipse by its center and radius.
They all represent graphic paths, and an ellipse can be represented as a
general path, so the graphic::ellipse->graphic::path conversion should be
implicit.
One may argue that the conversion from ellipse to general path does lose
the information of center and radius, but the domain here is GraphicPath,
in that sense, it's lossless.

On the other hand, consider:

asio::io_service io;
asio::ip::tcp::socket sock(io);

io_service and socket are orthogonal types. socket(io_service&) is
construction, as conversion doesn't make sense, so it should be explicit.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-22 09:01:24 UTC
Permalink
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm working
on that. https://github.com/tvaneerd/isocpp/blob/master/conversions.md
<https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Ftvaneerd%2Fisocpp%2Fblob%2Fmaster%2Fconversions.md&sa=D&sntz=1&usg=AFQjCNFc3HI_ClL1LZMdrntQuvVBLXBzAg>
In addition to 'not cheap', the constructor could throw. ‎Throwing from
'unseen' code is (somewhat) harder to deal with.
I think if we had string_view earlier, then string from char * probably
would have been explicit as well.
I believe that the only criteria that should be used to choose between
implicit and explicit conversion are correctness (being the same "platonic"
thing) and safety (e.g. narrowing conversions are not safe). Performance
and the possibility of exceptions should not be of any concern.

Regarding performance, if conversion from A -> B is correct and safe, it
should be viewed in the same way as a copy operation of A -> A. We don't
make copies explicit if they breach some "performance impact" threshold.
And how would we determine such a threshold anyway? Different users have
different performance requirements.

Regarding exceptions, exceptions occur in exceptional circumstances, and
should not be expected during regular program operation. As such,
exceptions are generally dealt with somewhere high up the call stack, not
at the point at which they are thrown. And anyway, I am skeptical of the
premise that if the programmer is forced to write `std::string(sv)` then
they will automatically know that this conversion can throw. Especially
with an exception as rare as `std::bad_alloc`, the programmer is unlikely
to know that it might be thrown, and even if they do, they are unlikely to
care (unless they are working on a platform with severely restricted memory
resources, in which case they will be catching the exception somewhere up
the call stack as I mentioned).

Explicit conversions represent a suppression of the type system. They are
the programmer telling the compiler, "Look, I know this doesn't seem safe,
but trust me, I've got this". An explicit conversion like `std::string(sv)`
is the same as `static_cast<std::string>(sv)`. Forcing users to explicitly
convert `string_view` to `string` is forcing them to suppress the safety
provided by the type system, despite the fact that the conversion is
actually correct and safe! If at some point in the future the type of `sv`
changes such that the conversion is no longer correct or safe, they will
not be warned about it by the compiler.

Last reason (I need to add this to my paper somewhere) -
Post by Tony V E
we want to encourage string_view use, discourage string. Wherever you are
doing that conversion, you should be thinking 'could I instead turn that
string into a string_view?'
Making `string_view` awkward to use will discourage its use IMO.

Sent from my BlackBerry portable Babbage Device
Post by Tony V E
*From: *TONGARI J
*Sent: *Tuesday, March 14, 2017 4:15 AM
*To: *ISO C++ Standard - Discussion
*Subject: *[std-discussion] Why string_view->string is explicit?
Creating a string from a string_view is not cheap, so it should be explicit
But given that we already have an implicit ctor that takes a char-pointer,
I don't think that argument makes sense (unless you also want to deprecate
that one).
I think the ease of use is more feasible than some unintuitive restriction.
Has this ever been discussed in the standard committee?
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at
https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Vicente J. Botet Escriba
2017-03-23 06:52:52 UTC
Permalink
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm
working on that.
https://github.com/tvaneerd/isocpp/blob/master/conversions.md
<https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Ftvaneerd%2Fisocpp%2Fblob%2Fmaster%2Fconversions.md&sa=D&sntz=1&usg=AFQjCNFc3HI_ClL1LZMdrntQuvVBLXBzAg>
In addition to 'not cheap', the constructor could throw. ‎Throwing
from 'unseen' code is (somewhat) harder to deal with.
I think if we had string_view earlier, then string from char *
probably would have been explicit as well.
I believe that the only criteria that should be used to choose between
implicit and explicit conversion are correctness (being the same
"platonic" thing) and safety (e.g. narrowing conversions are not
safe). Performance and the possibility of exceptions should not be of
any concern.
I think that the performance and the exception safety criteria should be
compared to the ones of the ToType copy constructor.
In this case they have the same performance and exception safety.

If we have this signature
|
voidf(string);
|

calling with string, string_view or const char* has almost the same
performances and exceptions safety.

However C++ is not only a copy semantic language.

|
voidf(stringconst&);

|

|
|


When you have a function that takes a parameter by lvalue reference, we
can avoid the copy when we have already a string.
But it is not the same for string_view or const char*. This is why in
those cases we need to add a new overload

|voidf(string_view);|

Once you have this overload you don't need anymore the implicit
conversion. Don't providing is forcing you to add this overload that is
more efficient and exception-safe.

If the language made the difference between a conversion from U to T
because we need a T and a conversion from U to T because we need a T
const& one could be implicit and the other explicit.
Post by Tony V E
Regarding performance, if conversion from A -> B is correct and safe,
it should be viewed in the same way as a copy operation of A -> A. We
don't make copies explicit if they breach some "performance impact"
threshold. And how would we determine such a threshold anyway?
Different users have different performance requirements.
This is the problem. We cannot.
Post by Tony V E
Regarding exceptions, exceptions occur in exceptional circumstances,
and should not be expected during regular program operation. As such,
exceptions are generally dealt with somewhere high up the call stack,
not at the point at which they are thrown. And anyway, I am skeptical
of the premise that if the programmer is forced to write
`std::string(sv)` then they will automatically know that this
conversion can throw. Especially with an exception as rare as
`std::bad_alloc`, the programmer is unlikely to know that it might be
thrown, and even if they do, they are unlikely to care (unless they
are working on a platform with severely restricted memory resources,
in which case they will be catching the exception somewhere up the
call stack as I mentioned).
Compilers can optimize code in case the code is noexcept. Using a
function that takes string_view instead will help.
Post by Tony V E
Explicit conversions represent a suppression of the type system. They
are the programmer telling the compiler, "Look, I know this doesn't
seem safe, but trust me, I've got this". An explicit conversion like
`std::string(sv)` is the same as `static_cast<std::string>(sv)`.
Forcing users to explicitly convert `string_view` to `string` is
forcing them to suppress the safety provided by the type system,
despite the fact that the conversion is actually correct and safe! If
at some point in the future the type of `sv` changes such that the
conversion is no longer correct or safe, they will not be warned about
it by the compiler.
I understand your concerns, and maybe we need an additional Friendly
criteria. However in this particular case I wouldn't use an implicit
conversion, as the goal of string_view was, just that, perform better
and without exceptions when we need a string const.
Post by Tony V E
Last reason (I need to add this to my paper somewhere) -
we want to encourage string_view use, discourage string. Wherever
you are doing that conversion, you should be thinking 'could I
instead turn that string into a string_view?'
Making `string_view` awkward to use will discourage its use IMO.
This view would change when people adapt its string const& to
string_view. This could take time, but I believe it is the way to go.

Best,
Vicente
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
TONGARI J
2017-03-23 07:50:34 UTC
Permalink
On Thursday, March 23, 2017 at 2:52:55 PM UTC+8, Vicente J. Botet Escriba
This view would change when people adapt its string const& to string_view.
This could take time, but I believe it is the way to go.
Functions that takes "string const&" probably would never vanish as long as
we have to deal with traditional C functions that takes "char const*" which
is assumed to be null-terminated.
In that case, "string const&" is the best choice since it's guaranteed to
be null-terminated.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-23 15:49:09 UTC
Permalink
Post by TONGARI J
On Thursday, March 23, 2017 at 2:52:55 PM UTC+8, Vicente J. Botet Escriba
Post by Vicente J. Botet Escriba
This view would change when people adapt its string const& to
string_view. This could take time, but I believe it is the way to go.
Functions that takes "string const&" probably would never vanish as long
as we have to deal with traditional C functions that takes "char const*"
which is assumed to be null-terminated.
In that case, "string const&" is the best choice since it's guaranteed to
be null-terminated.
I wrote a `zstring_view` class for exactly this purpose. It's almost
exactly like `string_view`, except that it's guaranteed to be
null-terminated. And it removes/modifies a few APIs to ensure this (you
can't remove characters from the end of a `zstring_view`, and sub-stringing
it returns a `string_view`).
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-23 08:58:01 UTC
Permalink
Post by j***@gmail.com
Post by Tony V E
We don't have guidelines for when to be implicit or explicit. I'm working
on that. https://github.com/tvaneerd/isocpp/blob/master/conversions.md
<https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Ftvaneerd%2Fisocpp%2Fblob%2Fmaster%2Fconversions.md&sa=D&sntz=1&usg=AFQjCNFc3HI_ClL1LZMdrntQuvVBLXBzAg>
In addition to 'not cheap', the constructor could throw. ‎Throwing from
'unseen' code is (somewhat) harder to deal with.
I think if we had string_view earlier, then string from char * probably
would have been explicit as well.
I believe that the only criteria that should be used to choose between
implicit and explicit conversion are correctness (being the same "platonic"
thing) and safety (e.g. narrowing conversions are not safe). Performance
and the possibility of exceptions should not be of any concern.
I think that the performance and the exception safety criteria should be
compared to the ones of the ToType copy constructor.
In this case they have the same performance and exception safety.
If we have this signature
void f(string);
calling with string, string_view or const char* has almost the same
performances and exceptions safety.
However C++ is not only a copy semantic language.
void f(string const&);
When you have a function that takes a parameter by lvalue reference, we
can avoid the copy when we have already a string.
But it is not the same for string_view or const char*. This is why in
those cases we need to add a new overload
void f(string_view);
Once you have this overload you don't need anymore the implicit
conversion. Don't providing is forcing you to add this overload that is
more efficient and exception-safe.
I posted an example in reply to Nicol using this exact case (adding extra
overloads) where the lack of an implicit conversion results in reduced
efficiency and exception safety. As I mentioned, casting (as the name
implies) makes code rigid and inflexible, and prevents the type system from
doing its job correctly. Casting should be reserved for conversions that
are not strictly correct or are unsafe.
Post by j***@gmail.com
If the language made the difference between a conversion from U to T
because we need a T and a conversion from U to T because we need a T
const& one could be implicit and the other explicit.
Regarding performance, if conversion from A -> B is correct and safe, it
should be viewed in the same way as a copy operation of A -> A. We don't
make copies explicit if they breach some "performance impact" threshold.
And how would we determine such a threshold anyway? Different users have
different performance requirements.
This is the problem. We cannot.
You can disable copy construction/assignment and replace it with a `clone`
method. This way users can't accidentally make an expensive copy. Would you
recommend this for any type that is expensive to copy? If so, how would you
recommend library designers determine what constitutes "expensive"?
Post by j***@gmail.com
Regarding exceptions, exceptions occur in exceptional circumstances, and
should not be expected during regular program operation. As such,
exceptions are generally dealt with somewhere high up the call stack, not
at the point at which they are thrown. And anyway, I am skeptical of the
premise that if the programmer is forced to write `std::string(sv)` then
they will automatically know that this conversion can throw. Especially
with an exception as rare as `std::bad_alloc`, the programmer is unlikely
to know that it might be thrown, and even if they do, they are unlikely to
care (unless they are working on a platform with severely restricted memory
resources, in which case they will be catching the exception somewhere up
the call stack as I mentioned).
Compilers can optimize code in case the code is noexcept. Using a function
that takes string_view instead will help.
That's true, but it has nothing to do with what we are talking about.
Post by j***@gmail.com
Explicit conversions represent a suppression of the type system. They are
the programmer telling the compiler, "Look, I know this doesn't seem safe,
but trust me, I've got this". An explicit conversion like
`std::string(sv)` is the same as `static_cast<std::string>(sv)`. Forcing
users to explicitly convert `string_view` to `string` is forcing them to
suppress the safety provided by the type system, despite the fact that the
conversion is actually correct and safe! If at some point in the future the
type of `sv` changes such that the conversion is no longer correct or
safe, they will not be warned about it by the compiler.
I understand your concerns, and maybe we need an additional Friendly
criteria. However in this particular case I wouldn't use an implicit
conversion, as the goal of string_view was, just that, perform better and
without exceptions when we need a string const.
You achieve this goal even if you enable the conversion.
Post by j***@gmail.com
Last reason (I need to add this to my paper somewhere) -
Post by Tony V E
we want to encourage string_view use, discourage string. Wherever you are
doing that conversion, you should be thinking 'could I instead turn that
string into a string_view?'
Making `string_view` awkward to use will discourage its use IMO.
This view would change when people adapt its string const& to string_view.
This could take time, but I believe it is the way to go.
I still think it will hurt adoption. `string_view` should interoperate
smoothly with existing code.
Post by j***@gmail.com
Best,
Vicente
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Chris Hallock
2017-03-23 16:53:35 UTC
Permalink
You want an implicit conversion from string_view to string. Do you also
want 3rd-party string types to be implicitly constructable from string_view?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Joseph Thomson
2017-03-23 17:01:02 UTC
Permalink
On 24 Mar 2017 12:53 am, "Chris Hallock" <***@gmail.com>
wrote:

You want an implicit conversion from string_view to string. Do you also
want 3rd-party string types to be implicitly constructable from string_view?


That's up to the authors of those string types. The conversion can be
implemented as a constructor of the 3rd party type, so `string_view`
doesn't have to worry about it.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-23 18:56:25 UTC
Permalink
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do you also
want 3rd-party string types to be implicitly constructable from string_view?
That's up to the authors of those string types. The conversion can be
implemented as a constructor of the 3rd party type, so `string_view`
doesn't have to worry about it.
The explicit conversion from `string_view` to `string` is implemented in
`string`, not `string_view`. As would be the implicit form. Since
`string_view` is the more fundamental type, it is the higher-level types
that have to provide conversions from and to `string_view`.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 01:25:45 UTC
Permalink
Post by Nicol Bolas
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do you also
want 3rd-party string types to be implicitly constructable from string_view?
That's up to the authors of those string types. The conversion can be
implemented as a constructor of the 3rd party type, so `string_view`
doesn't have to worry about it.
The explicit conversion from `string_view` to `string` is implemented in
`string`, not `string_view`. As would be the implicit form. Since
`string_view` is the more fundamental type, it is the higher-level types
that have to provide conversions from and to `string_view`.
I agree, but this is the only real option, unless there were some formally
defined `String` concept that could be checked at compile-time.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Chris Hallock
2017-03-23 19:05:08 UTC
Permalink
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do you also
want 3rd-party string types to be implicitly constructable from string_view?
That's up to the authors of those string types. The conversion can be
implemented as a constructor of the 3rd party type, so `string_view`
doesn't have to worry about it.
Of course, but do you have a *recommended design direction* with respect to
whether any string type (not just std::string) should implicitly construct
from string_view?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Matthew Woehlke
2017-03-23 19:28:13 UTC
Permalink
(@Joseph, can you please configure your mailer to quote properly? There
is zero distinction between your text and text to which you are replying...)
Post by Chris Hallock
Post by Joseph Thomson
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do
you also want 3rd-party string types to be implicitly
constructable from string_view?
That's up to the authors of those string types. The conversion can
be implemented as a constructor of the 3rd party type, so
`string_view` doesn't have to worry about it.
Of course, but do you have a *recommended design direction* with
respect to whether any string type (not just std::string) should
implicitly construct from string_view?
Here's a silly suggestion... implicit conversion constructions should be
consistent.

I find it strange that these:

char* -> string : implicit
string -> char* : explicit
string_view -> string : explicit
string -> string_view : implicit

...would be inconsistent.
--
Matthew
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-24 00:37:51 UTC
Permalink
Post by Matthew Woehlke
is zero distinction between your text and text to which you are replying...)
Post by Chris Hallock
Post by Joseph Thomson
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do
you also want 3rd-party string types to be implicitly
constructable from string_view?
That's up to the authors of those string types. The conversion can
be implemented as a constructor of the 3rd party type, so
`string_view` doesn't have to worry about it.
Of course, but do you have a *recommended design direction* with
respect to whether any string type (not just std::string) should
implicitly construct from string_view?
Here's a silly suggestion... implicit conversion constructions should be
consistent.
char* -> string : implicit
string -> char* : explicit
string_view -> string : explicit
string -> string_view : implicit
...would be inconsistent.
There are a lot of factors that go into whether a conversion should be
implicit or explicit. While consistency is important, we must also look at
the differences between the things you want to analogize.

There are lots of APIs that take a `char*` which would not be an
appropriate target for an implicit conversion from `string`. This is in
large part due to the fact that `char` is overloaded to mean both
"character" and "byte". So an implicit conversion to `char*` is more
dangerous than an implicit conversion to a type that is similar in form to
`char*` but isn't actually a `char*`.

Conversion to `char*` also loses information, since it has no explicit
length, whereas conversion to `string_view` preserves all pertinent
information.

Pre-UDLs, I would argue that the implicit conversion from `char*` to
`string` was just an unfortunate necessity, for the sake of preserving user
sanity. But now that we can do `"Some String"s` to make `std::string`s, the
verbosity of the explicit conversion is no longer necessary for string
literals. So it would only be needed for cases where you get a `char*` from
someone else. So making it explicit would not be as painful of a thing.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Patrice Roy
2017-03-24 00:57:23 UTC
Permalink
string_view from string is essentially free. string from string_view is
not. We're talking two different beasts here, and it's good that one is
implicit and no cost and the other, where it seems like a good idea, is
explicit as it bears cost.

I can understand the discourse that tries to push for an implicit
construction of string from string_view, but I think it's preferable to
keep this conversion explicit, in order to avoid unforeseen costs.
Post by Nicol Bolas
Post by Matthew Woehlke
is zero distinction between your text and text to which you are replying...)
Post by Chris Hallock
Post by Joseph Thomson
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do
you also want 3rd-party string types to be implicitly
constructable from string_view?
That's up to the authors of those string types. The conversion can
be implemented as a constructor of the 3rd party type, so
`string_view` doesn't have to worry about it.
Of course, but do you have a *recommended design direction* with
respect to whether any string type (not just std::string) should
implicitly construct from string_view?
Here's a silly suggestion... implicit conversion constructions should be
consistent.
char* -> string : implicit
string -> char* : explicit
string_view -> string : explicit
string -> string_view : implicit
...would be inconsistent.
There are a lot of factors that go into whether a conversion should be
implicit or explicit. While consistency is important, we must also look at
the differences between the things you want to analogize.
There are lots of APIs that take a `char*` which would not be an
appropriate target for an implicit conversion from `string`. This is in
large part due to the fact that `char` is overloaded to mean both
"character" and "byte". So an implicit conversion to `char*` is more
dangerous than an implicit conversion to a type that is similar in form to
`char*` but isn't actually a `char*`.
Conversion to `char*` also loses information, since it has no explicit
length, whereas conversion to `string_view` preserves all pertinent
information.
Pre-UDLs, I would argue that the implicit conversion from `char*` to
`string` was just an unfortunate necessity, for the sake of preserving user
sanity. But now that we can do `"Some String"s` to make `std::string`s, the
verbosity of the explicit conversion is no longer necessary for string
literals. So it would only be needed for cases where you get a `char*` from
someone else. So making it explicit would not be as painful of a thing.
--
---
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/a/isocpp.org/group/std-
discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 01:16:51 UTC
Permalink
Post by Nicol Bolas
Post by Matthew Woehlke
is zero distinction between your text and text to which you are replying...)
Post by Chris Hallock
Post by Joseph Thomson
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do
you also want 3rd-party string types to be implicitly
constructable from string_view?
That's up to the authors of those string types. The conversion can
be implemented as a constructor of the 3rd party type, so
`string_view` doesn't have to worry about it.
Of course, but do you have a *recommended design direction* with
respect to whether any string type (not just std::string) should
implicitly construct from string_view?
Here's a silly suggestion... implicit conversion constructions should be
consistent.
char* -> string : implicit
string -> char* : explicit
string_view -> string : explicit
string -> string_view : implicit
...would be inconsistent.
There are a lot of factors that go into whether a conversion should be
implicit or explicit. While consistency is important, we must also look at
the differences between the things you want to analogize.
There are lots of APIs that take a `char*` which would not be an
appropriate target for an implicit conversion from `string`. This is in
large part due to the fact that `char` is overloaded to mean both
"character" and "byte". So an implicit conversion to `char*` is more
dangerous than an implicit conversion to a type that is similar in form to
`char*` but isn't actually a `char*`.
Conversion to `char*` also loses information, since it has no explicit
length, whereas conversion to `string_view` preserves all pertinent
information.
Pre-UDLs, I would argue that the implicit conversion from `char*` to
`string` was just an unfortunate necessity, for the sake of preserving user
sanity. But now that we can do `"Some String"s` to make `std::string`s, the
verbosity of the explicit conversion is no longer necessary for string
literals. So it would only be needed for cases where you get a `char*` from
someone else. So making it explicit would not be as painful of a thing.
I couldn't have said it better myself. Strictly, conversion from `char
const*` is incorrect, but it was a necessary fudge given the nastiness
inherited from C.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Matthew Woehlke
2017-03-24 14:20:36 UTC
Permalink
Post by Nicol Bolas
Post by Matthew Woehlke
char* -> string : implicit
string -> char* : explicit
string_view -> string : explicit
string -> string_view : implicit
...would be inconsistent.
Conversion to `char*` also loses information, since it has no explicit
length, whereas conversion to `string_view` preserves all pertinent
information.
In that sense, conversion from a char* to a string is hard, because you
have to count the characters to know the length. Having implicit
conversion from char* to string, but *not* from string_view to string,
is, in that respect... well, "questionable" would be putting it mildly...
Post by Nicol Bolas
Pre-UDLs, I would argue that the implicit conversion from `char*` to
`string` was just an unfortunate necessity, for the sake of preserving user
sanity. But now that we can do `"Some String"s` to make `std::string`s, the
verbosity of the explicit conversion is no longer necessary for string
literals. So it would only be needed for cases where you get a `char*` from
someone else. So making it explicit would not be as painful of a thing.
Then let's do that.
--
Matthew
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-03-24 15:10:02 UTC
Permalink
Post by Matthew Woehlke
Post by Nicol Bolas
Post by Matthew Woehlke
char* -> string : implicit
string -> char* : explicit
string_view -> string : explicit
string -> string_view : implicit
...would be inconsistent.
Conversion to `char*` also loses information, since it has no explicit
length, whereas conversion to `string_view` preserves all pertinent
information.
In that sense, conversion from a char* to a string is hard, because you
have to count the characters to know the length. Having implicit
conversion from char* to string, but *not* from string_view to string,
is, in that respect... well, "questionable" would be putting it mildly...
Post by Nicol Bolas
Pre-UDLs, I would argue that the implicit conversion from `char*` to
`string` was just an unfortunate necessity, for the sake of preserving
user
Post by Nicol Bolas
sanity. But now that we can do `"Some String"s` to make `std::string`s,
the
Post by Nicol Bolas
verbosity of the explicit conversion is no longer necessary for string
literals. So it would only be needed for cases where you get a `char*`
from
Post by Nicol Bolas
someone else. So making it explicit would not be as painful of a thing.
Then let's do that.
If there's an STL2 that replaces `basic_string`, then we can do that there.
But until then, it's just not worth the effort. A minor gain of consistency
isn't worth the pain of going through years of a deprecation/BC breakage
cycle.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 01:30:03 UTC
Permalink
Post by Matthew Woehlke
is zero distinction between your text and text to which you are replying...)
Really? I'm just using the plain old Gmail web client. It all looks okay to
me, both in Gmail and on Google Groups.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
j***@gmail.com
2017-03-24 01:20:19 UTC
Permalink
Post by Chris Hallock
Post by Chris Hallock
You want an implicit conversion from string_view to string. Do you also
want 3rd-party string types to be implicitly constructable from string_view?
That's up to the authors of those string types. The conversion can be
implemented as a constructor of the 3rd party type, so `string_view`
doesn't have to worry about it.
Of course, but do you have a *recommended design direction* with respect
to whether any string type (not just std::string) should implicitly
construct from string_view?
If the string type is essentially similar to `string`, then it would
probably be desirable to support conversion from `string_view`. There may
be additional considerations depending on the exact design of the string
type.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Matthew Woehlke
2017-05-26 19:53:31 UTC
Permalink
If you call three functions in a row that all need a string, maybe
you should only convert once instead of three times.
Maybe the optimizer could take care of that.
I doubt this is possible unless the compiler has intrinsic knowledge
that std::string construction/destruction doesn't have any other side
effects but copying the string.
"Pure" constructors? Is that feasible?
--
Matthew
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Andrey Semashev
2017-05-27 00:18:17 UTC
Permalink
On Fri, May 26, 2017 at 10:53 PM, Matthew Woehlke
Post by Matthew Woehlke
If you call three functions in a row that all need a string, maybe
you should only convert once instead of three times.
Maybe the optimizer could take care of that.
I doubt this is possible unless the compiler has intrinsic knowledge
that std::string construction/destruction doesn't have any other side
effects but copying the string.
"Pure" constructors? Is that feasible?
It would also require allocator and char_traits to be pure. Given that
both of them can be customized, you can't mark the constructor pure
straight away. You could mark a specialization for std::allocator and
std::char_traits, but I'd call that incomplete solution.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Matthew Woehlke
2017-05-26 20:01:35 UTC
Permalink
If I am faced with a API taking `string const&` that I cannot change to
take `string_view` (this is likely to be a common scenario), I am left with
no option but to cast to `string`. If at some later date, the maintainer of
the API decides to use `string_view`, I now have a silent *explicit*
conversion that I wouldn't have had if the conversion had been implicit.
Yes, the API maintainer could keep and deprecate (with `[[deprecated]]`)
the old version, but do you really want to rely on them following the
correct procedure?
...so now, instead, everywhere I already had a string, I have to
explicitly cast it to a string_view to avoid a deprecation warning?

That'll go over well. More likely, library authors won't punish their
users in this way, and we will indeed have introduced inefficient code
by making string_view → string explicit.
--
Matthew
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Olaf van der Spek
2017-05-29 08:59:18 UTC
Permalink
Post by Matthew Woehlke
If I am faced with a API taking `string const&` that I cannot change to
take `string_view` (this is likely to be a common scenario), I am left with
no option but to cast to `string`. If at some later date, the maintainer of
the API decides to use `string_view`, I now have a silent *explicit*
conversion that I wouldn't have had if the conversion had been implicit.
Yes, the API maintainer could keep and deprecate (with `[[deprecated]]`)
the old version, but do you really want to rely on them following the
correct procedure?
...so now, instead, everywhere I already had a string, I have to
explicitly cast it to a string_view to avoid a deprecation warning?
That'll go over well. More likely, library authors won't punish their
users in this way, and we will indeed have introduced inefficient code
by making string_view → string explicit.
I've got a function that needs a std::string but I'm actually using
string_view as parameter type to avoid cluttering call-sites..
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Thiago Macieira
2017-05-25 21:12:58 UTC
Permalink
The C++ Core Guidelines are driving pretty hard for the development of
static analysis tools to enforce its rules. VS 2017 came with the first
version of Microsoft's such a tool. I'm proposing that a rule(s) be added
to the guidelines, so that the check becomes standard in the future.
Or, phrased more directly to answer my question, "none"
I don't see what this proves. I'm still proposing a viable alternative
solution that could easily be realised in the near future.
But which no one has, not even a similar feature. So we don't even know if it
is something static analysers could provide.

And then there's the problem that, like I said, most people don't use static
analysers.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Loading...