Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - reconn

Pages: [1]
1
SFML development / Re: Introduce chrono to sf::Time
« on: December 25, 2021, 07:37:57 pm »
Yes, that is my PR. Can you elaborate more?

2
SFML development / Introduce chrono to sf::Time
« on: December 23, 2021, 05:44:30 pm »
sf::Time and chrono library

To keep SFML simple, explicit but up-to-date with the features of the STL, the introduction/integration of <chrono> would be of help to some.

sf::Time is a simple self-contained class, therefore, does not (yet) allow the chrono literal conversions, operator overloads, etc.

I propose to carefully define/discuss an extended API for sf::Time (and sf::sleep function) that extends sf::Time by the chrono library. Moreover, since <chrono> would be included already, sf::Time could possibly benefit from it internally (unsure of that though).

New allowed conversions and overloads:
// Currently
sf::Time t1 = sf::milliseconds(1001);
// Extended capabilities after e.g., using namespace std::chrono_literals;
sf::Time t2 = 1001ms;
sf::Time t3(1001ms);
sf::Time t4 = 1s + 1ms;
t1 += 1ms;

// Resulting type: sf::Time or std::chrono::duration?
// How about sf::Time with implicit conversion to chrono?
auto t5 = sf::seconds(1) + 1s;

Integrating Chrono makes sense only partially as it itself is very flexible but with some serious drawbacks. Consider these two examples readability- and convenience-wise:

/* Example 1 */
using namespace sf;
Time t = milliseconds(1001);
std::cout << "Time: " << t.asSeconds() << " second(s)\n";
// Output: Time: 1.001 second(s)

/* Example 2 */
using namespace std::chrono;
duration t = milliseconds(1001);
std::cout << "Time: " << duration<float>(t).count() << " second(s)\n";
// Output: Time: 1.001 second(s)

Chrono is more explicit so for a library developer it is quite useful to know what is/isn't going on but the user is bloated with unnecessary information. However, carefully providing chrono extensions could synergize well with other modern libraries.

Rising questions and concerns
- Would Time really benefit from chrono internally? (Probably would have to implement first to find out)
- Does SFML want to keep implicit narrowing conversions and overflows in sf::Time? (Those are edge cases but still exist)
- Would SFML like to introduce asNanoseconds?
- How will compilation time be affected? (Hopefully not much)

3
SFML development / Re: sf::NonCopyable and =delete
« on: December 09, 2021, 02:52:33 am »
I believe sf::NonCopyable does more harm than good in the long run. Early/inexperienced developers will definitely inspect SFML code and get inspired by the idioms they see here. I think SFML should continue promoting good C++.

That said, seeing sf::NonCopyable - how simple, useful and concise it is - some may think it's a great idea. But sf::NonCopyable is in fact a code smell, syntactic sugar. The class can be inherited publicly which causes trouble with polymorphic destruction of base classes, and even the documentation says public inheritance does not matter here:
Quote
/// The type of inheritance (public or private) doesn't matter,
/// the copy constructor and assignment operator are declared private
/// in sf::NonCopyable so they will end up being inaccessible in both
/// cases.

To be safe it would require a virtual destructor which imposes an additional cost. Sure, private inheritance is safe but it's still ambiguous when somebody inherits directly from NonCopyable but provides a copy constructor or adds default move constructor/assignment anyways which separates statements of the move "=delete"s from NonCopyable.

All that mess for questionable readability/simplicity.

4
SFML development / Re: Sensible use of certain C++17 features
« on: December 09, 2021, 02:18:01 am »
Well described! I do support and agree with most of what you said. Sensible use but taking advantage when it matters.

I would add that other uses for noexcept come when an exception should not happen because it will never be caught anyways. For example, "threaded functions" like in void SoundStream::streamData().

Regarding auto/type deduction. C++17 also added CTAD which helps with readability when both auto and explicit type are clunky. So as an advice, if auto seems to be a good idea, maybe check if CTAD isn't better. Example:
// here: it's better to use auto
auto renderTextureImpl = std::make_unique<RenderTextureImplDefault>();
// and now transfer ownership
auto otherImpl = std::move(renderTextureImpl);  // less obvious that it's a pointer
std::unique_ptr<RenderTextureImplDefault> otherImpl = std::move(renderTextureImpl);  // too verbose type
std::unique_ptr otherImpl = std::move(renderTextureImpl);  // somewhere in the middle
 
or
std::scoped_lock lock(m_mutex);
// vs.
std::scoped_lock<std::mutex> lock(m_mutex);
 

5
SFML development / Re: SFML Move Semantics
« on: December 05, 2021, 10:04:14 pm »
If I may introduce my point and suggestions.

First of all, I agree with copy-and-swap in advance.

Second of all, C++ programmers often make the mistake of supplying classes with too much noise (defining empty destructors, implementing default copy/move constructors, and default assignment operator overloads) which does more harm than good for readability and maintainability.

The rule of thumb should be to default to the Rule of Zero. Only when it does not suffice, fallback to the Rule of Three or Five (preferably) starting with compiler defaults ("= default") or Four-and-a-Half even. It is most intuitive when the noise is removed. An empty non-virtual destructor makes the class non-trivially destructible from the Standard's point of view. A non-noexcept move constructor makes the class non-no-throw-move-constructible.

The question could come: why be strict about the noexcept specifier in move semantics? Because STL utilizes this mechanic AND most importantly it assures that the move construction/assignment is intuitive. If a class can not afford a noexcept move constructor/assignment then it is unable to simply/intuitively transfer its states thus should not use move semantics but a transfer mechanism of some sort. A move constructor/assignment should only do simple transfers. No heap allocations, no checks, no side-effects. Only then it is intuitive.

Should a class need a "move semantic" function with a possible exception - one could write a member function for that purpose and not utilize move constructors/assignment operators.

// Ways of transferring object states in std::unique_ptr
auto ptr = std::make_unique<int>(7);
// a) "Move semantic" transfer
auto otherPtr = std::move(ptr);
// b) A transfer mechanism which does not need to impose noexcept
auto anotherPtr = std::unique_ptr<int>(ptr.release());
 

Of course, this is an example of std::unique_ptr which has noexcept `release()` function. However, this is just to show how it can be accomplished/worked around to keep a strong exception guarantee on move semantics.

Pages: [1]