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

Author Topic: Change Unit of Measure  (Read 23903 times)

0 Members and 2 Guests are viewing this topic.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Change Unit of Measure
« Reply #30 on: July 13, 2013, 12:17:33 am »
Do you think it would make more sense for asRadians() to return a double? I'd hate to have errors due to lack of precision on those.
I don't think so, because SFML uses floats everywhere else, and the matrix pushed to OpenGL stores floats, too. It would only help if you performed heavy computations on user side.

Take sf::Time for example. Someone could write something like sf::sleep( sf::seconds( m_sleep_time ) ) in their main. In some other file at line 1337, they might set m_sleep_time to 1000. Do they realize that they have committed an error? No, because they were lazy, and nothing about sf::Time will prevent it from happening.
What you are saying, is that sf::Time cannot prevent errors that occur because sf::Time is not used. Yes, of course that is true.

If, however, they had to construct the sf::Time using a user-defined literal every time, they wouldn't be allowed to do stupid things [...]
They still are. You cannot remove the existing factory functions unless you enforce the ugly syntax mentioned by Silvah. Imagine the users have to convert a float read from a file to a sf::Time. If they are not able to choose the correct factory, the resulting time will be wrong.
« Last Edit: July 13, 2013, 12:19:05 am by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Klaim

  • Full Member
  • ***
  • Posts: 137
    • View Profile
Re: Change Unit of Measure
« Reply #31 on: July 13, 2013, 02:17:25 am »
Do you need to know the angle type? Not really...

I disagree.

Quote
if you want to pass an angle in degrees, mark it with _deg, if you want radians then _rad.

Which, in a typed context, is exactly a shortcut for Degree(value) and Radian(value). Please check what UDL is really, because I think you don't understand it nor do you understand strong typing.

Quote
You don't need to rely on the implicit type if you don't want to.

If you don't want to use a degree value into an object which is interpret on read as a radian value, you want it typed.


Quote
As an example, you could pass shorts around as 10_s if that makes it more clear you intend on it being interpreted as a short as opposed to an int or what not (this is really useful when trying to pack short literals into an sf::Packet without explicit casting).

I agree, as I was saying, UDL is nothing else than shortcut conversion from source code litteral to a typed value. If you use double or float or any basic type, your conversion is just meaningless in specific context, but useful if it's exactly what you meant, which is why there is already the default litterals L, l,  f etc.

Quote
User-defined literals are not meant as a way to prevent errors by passing PODs around.

Exactly, you need strong typing to prevent these errors. Whatever the way you can't avoid defining one (sf::Angle) or N types (Ogre::Degree/Radian). You can't use int or float and assume everybody will know it's degree and will never make mistakes.

Quote
If you wanted that, all functions would take some kind of an Angle type but since this topic was about being able to pass different units to functions without worrying about conversions, user-defined literals solves that problem completely.

Not if the compiler can't know the difference. You see, if your function takes a radian as float, and you provide say "90deg" and  you have UDL converting it to a float, then you used UDL to give your intent but the code will compile and not do what you intended.
Which is why you need strong typing.

Quote
User-defined literal is quite literally what the name implies, a mechanism for you do define your own kinds of literals.

We strongly agree.

Quote
Literals aren't bound to a type until they are put into a certain context.

No, litteral are strictly always bound to a type, which is what makes auto works in the first place:

Code: [Select]
auto a = 42; // int
auto b = 42.0; // double
auto c = 42.0f; // float
auto d = 42L; // long (or long)  etc.

Quote
That is why your literal handling function gets nothing but the string of characters straight out of your source code and it is up to you to interpret them in any way you want.

And return a type. So, basically UDL solve the ease of writing but types solve the identification of intent and basically allow you to see the points of conversion. If you use UDL to always return a sf::Angle, why not, but don't return a double or float, it's hiding the intent of the library developer side of the contract in the interface of the function.

Quote
You can make both _deg and _rad return some double value, be it in degrees, radians, gradian or whatever crazy unit you can think of. It just has to fit with the rest of the interface.

double, I disagree. A specific type, I agree.


By the way, UDL is a minor improvement here because most games are data-driven so the data were not in the code anyway. When you get the data to inject in SFML, I hope you know what type it is. I wouldn't trust mysefl with it, which is why I let the compiler make sure it's the right type.

sf::Time is nice, but it does force you to convert the value to something at the point of use.
The same applies to Degree and Radian classes, you have to call something like an asFloat() function as soon as you need to perform a computation with it.

Not at all, it provides all the necessary operators, even implicitely converting degree values to radians if you are mixing them in calculus (in which case you pay for mixing the types but it don't make the code uglier by forcing you to explicitely convert). Take a look at the header: https://bitbucket.org/sinbad/ogre/src/0bba4f7cdb953c083aa9e3e15a13857e0988d48a/OgreMain/include/OgreMath.h?at=default
Actually the conversion is implicit between Radian and Degree (I was wrong on this detail), but explicit when you provide a float value (which is where having UDL makes code shorter to read)

Ogre uses Radian by default internally and in all it's interface (which is configurable), which means if you use Radian in your user code then there is strictly no conversion hapening. If you use Degree in all your user code then at least one conversion happen when you push Degrees into Ogre. You can avoid it when you configure Ogre to use Degree but then it will have to convert to Radian before pushing it in the graphic card anyway.

Basically, no conversion until you use Degree. There are also operations on Vector and Matrix types in Ogre which rely on Radian which mean there again there is no conversion until you use Degree.

Which was my initial point with this design. I believe sf::Time/Angle don't have the same properties. I consider it's ok with Time because it's more about time scale and SFML don't work under microseconds and over seconds, so it's good. ( std::chrono necesarily needs to be more flexible and precise because far more generic )
However angles have two defined types which are not just scales so to me it's more obvious to have a different type for each, it fit the semantic and allows the no-conversion-if-same-type semantic.

Quote
That is currently the biggest drawback of such wrappers, every trigonometric function call requires an explicit conversion. The only way to cope with this consists of overloading a large number of functions.


I'm not sure I understand by overloading a large number of functions. If a specific type is used into SFML (or Ogre) for angles, then there is no need for overload, isn't it?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Change Unit of Measure
« Reply #32 on: July 13, 2013, 02:40:00 am »
Not at all, it provides all the necessary operators, even implicitely converting degree values to radians if you are mixing them in calculus
Yes, there are implicit conversions between each other, but many computations -- especially trigonometry -- are not covered. That is, you still have to write std::sin(angle.asRadians()), unless you overload all the functions, i.e. write functions that take sf::Angle and return float.


However angles have two defined types which are not just scales so to me it's more obvious to have a different type for each, it fit the semantic and allows the no-conversion-if-same-type semantic.
What do you mean? Radians and degrees are just different scales of an angle. The scaling factor is 180/pi.

I see a different problem with two types sf::Degree and sf::Radian: the amount of operators to overload increases by almost a factor of four. Instead of just providing binary operators like Angle + Angle, the following combinations need to be covered:
  • Degree + Degree
  • Degree + Radian
  • Radian + Degree
  • Radian + Radian
And this applies to many arithmetic and relational operators. Without helpers such as Boost.Operators, the implementation results in masses of boilerplate code and code duplication.

On the other hand, I see only one advantage of two types: assuming sf::Angle stores radians and the user converts a lot between raw floats and degrees, there is an unnecessary conversion between degree and radian, which could be avoided with sf::Degree. But in my opinion, this alone isn't worth the trouble and the confusion with two types to describe an angle.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Klaim

  • Full Member
  • ***
  • Posts: 137
    • View Profile
Re: Change Unit of Measure
« Reply #33 on: July 14, 2013, 03:31:46 pm »
Indeed it requires a lot of overloads. Ogre manage this by having it's own math library (which is a modified version of an old math library called Magic Box if I remember correctly).
If this is a problem then sf::Angle is certainly a good enough solution.