Skip to content

Conversation

@yves-dolce
Copy link
Contributor

@yves-dolce yves-dolce commented Jul 10, 2019

  • removing noexcept from methods where an exception could be raised.
    If std::terminate() call is desired instead, I guess those should be
    left and std::move_if_noexcept() used to document the fact that it's
    on purpose.
  • std::move local variable into argument when possible.
  • change maxversiontested XML element to maxVersionTested.
  • used of gsl::narrow_cast where appropriate to prevent warnings.
  • fixed bug in TerminalSettings::SetColorTableEntry()

Summary of the Pull Request

References

PR Checklist

  • Closes Profile::Set...(std::wstring param) not using std::move #1844
  • CLA signed. If not, go over here and sign the CLA
  • Tests added/passed
  • Requires documentation to be updated
  • I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

-  removing noexcept from methods where an exception could be raised.
   If std::terminate() call is desired instead, I guess those should be
   left and std::move_if_noexcept() used to document the fact that it's
   on purpose.
- std::moving local variable into argument when possible.
- change maxversiontested XML element to maxVersionTested.
- used of gsl::narrow_cast where appropriate to prevent warnings.
- fixed bug in TerminalSettings::SetColorTableEntry()
@msftclas
Copy link

msftclas commented Jul 10, 2019

CLA assistant check
All CLA requirements met.

Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly have some questions, otherwise this largely looks fine.

{
auto pwshProfile{ _CreateDefaultProfile(L"PowerShell Core") };
pwshProfile.SetCommandline(psCoreCmdline);
pwshProfile.SetCommandline(std::move(psCoreCmdline));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiousity, how does line 206 (above) work?

powershellProfile.SetCommandline(L"powershell.exe");

Does it create a new wstring using the string literal to initialize it, then immediately move it to the function call? (not saying this is wrong, I just don't know)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precisely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, this effectively means that if the creation of the string raises an exception, it will happen at the call site, in CascadiaSettings::_CreateDefaultProfiles(), not in Profile::SetCommandLine() (which is rightfully noexcept).


// If we don't have that many profiles, then do nothing.
if (realIndex >= profiles.size())
if (realIndex >= gsl::narrow_cast<decltype(realIndex)>(profiles.size()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason to use decltype(realIndex) over manually stating the type of realIndex?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the type is changed for any reason, one would not need to also change that line.
That said, this was a small mistake as I should have used gsl::narrow instead. It will raise an exception if the cast would change the value in any way. (see gsl_util).
I'll wait for you feedback to make the change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems correct to me. I love decltype.

void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept
{
_schemeName = schemeName;
static_assert(noexcept(_schemeName = std::move(schemeName)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait what does this do? I don't think I'm familiar with using noexcept() as a function like that.

Copy link
Contributor Author

@yves-dolce yves-dolce Jul 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only been using it a couple of times myself. 😉
See noexcept operator.
It just documents the fact that line 450 does not raise any exception. If anything changes in std::optional or std::wstring implementations and an exception could be raised, line 449 would effectively raise an error during build time.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion only 😄 - although 100% correct - code that checks to see if standard C++ code is C++ complaint is overkill and adds unnecessary complexity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we shouldn't need to validate that C++ code is C++ compliant!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.
FWIW, it's about the implementation of the std::optional move constructor which I believe was not marked as noexcept till C++ 17.
I find that static_assert statement to be easier than starting to read the C++ standard. ;-)

void Profile::SetIconPath(std::wstring_view path) noexcept
void Profile::SetIconPath(std::wstring_view path)
{
static_assert(!noexcept(_icon.emplace(path)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to the above, what's this doing and why does this one have a ! in it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the flip side of the previous comment. Maybe it'd be clearer if I'd had the comment for each static_assert:

static_assert(noexcept(_schemeName = std::move(schemeName)), "Profile::SetColorScheme() is no longer noexcept!")
static_assert(!noexcept(_icon.emplace(path)), "Mark Profile::SetIconPath() as noexcept");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea a comment might be helpful, since I definitely read that code and assumed that it was asserting the opposite :P


// If we don't have that many profiles, then do nothing.
if (realIndex >= profiles.size())
if (realIndex >= gsl::narrow_cast<decltype(realIndex)>(profiles.size()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems correct to me. I love decltype.

void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept
{
_schemeName = schemeName;
static_assert(noexcept(_schemeName = std::move(schemeName)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we shouldn't need to validate that C++ code is C++ compliant!

// Arguments:
// - path: the path
void Profile::SetIconPath(std::wstring_view path) noexcept
void Profile::SetIconPath(std::wstring_view path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious here. This one uses wstring_view, and the others use wstring. Should we standardize on just one? If so, what do you think we should do, @yves-dolce?

Copy link
Contributor Author

@yves-dolce yves-dolce Jul 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the body of the method (e.g. Profile::SetIconPath) calls methods that support std::wstring_view, std::wstring_view will allow you not to have any heap allocation during the parameter passing. That class is just a pointer and a size after all.
But keep in mind that:

  • it does not enforce the string to be null terminated. Again, it's just a pointer to the beginning of the string and a length.
  • the compiler might have a harder time optimizing the calling site as now, you've created an alias. When you were taking a std;:wstring, no aliasing was created.

All in all, I'd personally stick with std::wstring, and std::move. I use std::wstring_view if I plan on having to interact with code that uses weird stuff and don't want to force heap allocation... (CString, bstr_t, CComBSTR, ...)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough! 👍

@yves-dolce
Copy link
Contributor Author

This is the first time I participate on an GitHub open source project.
Can you confirm that I shall merge the latest from master, fix the code base on your comments and push my fork and then this PR will automatically updated.
Is that correct?

@DHowett-MSFT
Copy link
Contributor

That's correct!

@yves-dolce
Copy link
Contributor Author

I pushed without compiling as my changes were very small.
I just tried anyway but I now get Mismatched C++/WinRT headers. static assertion failure: I have 2.0.190722.3.
What's the best way to fix this if I want to keep the latest version accessible for my own code?

@DHowett-MSFT
Copy link
Contributor

I believe you just need to Clean your local build and make sure you "restore nuget packages" again; our dependencies have been updated 😄

// Arguments:
// - path: the path
void Profile::SetIconPath(std::wstring_view path) noexcept
void Profile::SetIconPath(std::wstring_view path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough! 👍

<!-- Windows 10 1903 -->
<!-- See https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/xaml-islands -->
<maxversiontested Id="10.0.18362.0"/>
<maxVersionTested Id="10.0.18362.0"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm moderately worried about whether this is case sensitive. I'll check with the manifest team.

Copy link
Contributor Author

@yves-dolce yves-dolce Jul 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. I'm curious about that one as XML is case sensitive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wellp, it looks like it is case-sensitive. Somebody owes me a coke, I just haven't figured out who.

@yves-dolce
Copy link
Contributor Author

Are we just waiting for a 2nd reviewer?

Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with this, but since @DHowett-MSFT left some other comments, I'll let him be the second on this one.

void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept
{
_schemeName = schemeName;
_schemeName = std::move(schemeName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, this works with a std::optional too?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Blurb from cppreference.

Move constructor: If other contains a value, initializes the contained value as if direct-initializing (but not direct-list-initializing) an object of type T with the expression std::move(*other) and does not make other empty: a moved-from optional still contains a
value, but the value itself is moved from. If other does not contain a value, constructs an object that does not contain a value. This constructor does not participate in overload resolution unless std::is_move_constructible_v is true. It is a trivial constructor if std::is_trivially_move_constructible_v is true.

So in this case std::move() will cast the variable (schemeName) to an rvalue, allowing it to bind to a move constructor.

@miniksa
Copy link
Member

miniksa commented Aug 6, 2019

@DHowett-MSFT, this one is also waiting for you and otherwise looks good to go.

@miniksa miniksa added the Needs-Attention The core contributors need to come back around and look at this ASAP. label Aug 6, 2019
Copy link
Contributor

@DHowett-MSFT DHowett-MSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite comfortable with this now. Thank you for your contribution, and sorry it took us so long!

@DHowett-MSFT DHowett-MSFT merged commit dfb8536 into microsoft:master Aug 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs-Attention The core contributors need to come back around and look at this ASAP.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Profile::Set...(std::wstring param) not using std::move

7 participants