Date: Wed, 27 Jan 2021 10:51:05 +0000
Thank you for the information Peter 😊
As nice and well-done your framework is, it is still "yet another" approach to provide strong typing to C++.
Suppose I have created my own, and I use a library providing its own, and I use another library providing yours... Now I have at least 3 incompatible and competing "strong typing" frameworks in my software. Complexity, confusion... similar situation when you have to use geometric point types and you have to use several libraries, each providing their own ones 😊 glm::vec3 and Eigen::Vector3f are basically the same thing yet it's a pain if I have to combine them in a single algorithm, because using 3rd party libraries.
This is to illustrate my opinion that there's a real need to somehow provide a standard way to achieve the desired goal - here, strong typing.
Maybe, probably it can be done at the library level. However, a library implementation involves some more or less heavy template machinery, making it not so easy to use. Moreover it would probably increase compile time, which is usually not desirable (I daily work on softwares that typically need hours to build).
Also a library implementation implies some kind of tag to distinguish between the "strongly type types", either a value or an empty type. The management of these tags is put on the user's responsability, making it potentially difficult to avoid clashes with locally defined derived types and ones from a third party library.
That's why I thought an extension to the language would be more practical - although probably more work for compilers writers.
Regards,
Yves Bailly
Development engineer
Manufacturing Intelligence division
Hexagon
M: +33 (0) 6.82.66.09.01
HexagonMI.com
> -----Original Message-----
> From: Peter Sommerlad (C++) <peter.cpp_at_sommerlad.ch>
> Sent: Wednesday, January 27, 2021 11:31
> To: std-proposals_at_lists.isocpp.org; BAILLY Yves via Std-Proposals <std-
> proposals_at_[hidden]>
> Cc: BAILLY Yves <yves.bailly_at_hexagon.com>
> Subject: Re: [std-proposals] Explicit using --> Library for simple strong types
>
> This email is not from Hexagon’s Office 365 instance. Please be careful while
> clicking links, opening attachments, or replying to this email.
>
>
> FWIW, I created a very simple to use strong typing framework for C++17 that
> allows to create strong types with respective selection of appropriate operators
> on a single line, such as
>
> struct Word:strong<std::string,Word, Out, Add, Order>{};
>
> struct literGas:strong<double,literGas,Additive,Order,Out>{
> constexpr static inline auto suffix=" l";
> };
> the suffix static member is for output customization.
>
> Available at
> https://eur02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.c
> om%2FPeterSommerlad%2FPSsst&data=04%7C01%7C%7C134ffe8c24384
> 7ad5e3e08d8c2aeaba5%7C1b16ab3eb8f64fe39f3e2db7fe549f6a%7C0%7C0%
> 7C637473402750776770%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAw
> MDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdat
> a=TjsDb4SSwerQuv8A8%2B2SniCDv00deU3KxA7VbSbqbtI%3D&reserved=
> 0
>
> So I see little need in the language change, but I also did not follow the
> discussed details.
>
> Regards
> Peter.
>
> BAILLY Yves via Std-Proposals wrote on 27.01.21 11:22:
> > I think I get your point. After more thinking about it (which I should
> > have done before, sorry for that), then in short, I would say when
> > writing
> >
> > *using U = new T;*
> >
> > …then yes, *U* is a new type different from *T* – although referring
> > to the same Platonic type as *T*.
> >
> > This implies that indeed, *std::is_same<T,U>* is different from
> > *std::is_same<T,T>* and *std::is_same_v<T,U> == std::is_same_v<U,T> ==
> > false*.
> >
> >> For example:
> >
> >> template<class A> void f(A a);
> >
> >> f(T{}); // #1
> >
> >> f(U{}); // #2
> >
> >> Does #1 call f<T>? (Yes, it must.)
> >
> > Yes.
> >
> >> Does #2 call f<U>? (I don't know but I think so.)
> >
> > Yes, because it’s given a *U*.
> >
> >> Is f<U> the same function as, or a different function from, f<T>? (I
> >> don't know but I think so.)
> >
> > If *T* and *U* are two different types, then *f<U>* is a different
> > function from *f<T>*.
> >
> > /However,/ because *U* and *T* refer to the same Platonic type and a
> > *U* can be seen as a *T*, then if *f<U>* is syntactically correct,
> > well-formed with regard to the restrictions put on U (for example,
> > inside *f<>* there’s no assignment of a *T* to a *U* without an
> > explicit cast), then the actual instantiation of *f<U>* can be the
> > same as the instantiation of *f<T>* - in a way, *f<U> = f<T>*. Put in
> > another way, if we assume *f<T>* has already been created, then the
> > compiler would create a new “envelop” named *f<U>* but with the same
> > contents as *f<T>* – unless of course some explicit specialization
> > *f<U>* is provided by the user.
> >
> > This would apply to the *std::hash<>* specialization: when required to
> > instantiate *std::hash<U>*, if it has not been explicitly specialized,
> > then as you said the compiler may realize that *std::hash<U>* is the
> > same (has the same contents although it doesn’t have the same
> > identity) as *std::hash<T>* - again, if and only if the code for
> > *std::hash<U>* is well-formed and there’s no explicit specialization
> > defined provided by the user.
> >
> >> using Height = new int;
> >
> >> using Tilt = new int;
> >
> >> void increaseAltitude(Height h);
> >
> >> void increaseAttitude(Tilt t);
> >
> >> ...
> >
> >> Height h;
> >
> >> increaseAttitude(h); // oops — but, since increaseAttitude takes a Tilt, this
> happily won't compile!
> >
> >>
> >
> >> However, it doesn't seem to protect us against
> >
> >> Height h;
> >
> >> Tilt t;
> >
> >> t += h; // oops — and this silently calls the built-in candidate
> >>operator+=(int&, int)
> >
> > That’s true indeed, no more protection here than when using
> > “traditional” typedefs. And I see how this can indeed be seen as a
> > “massive inconsistency” between *t=h* (not OK) and *t+=h* (OK).
> >
> > However, I would argue the situation is still better than when using
> > “standard” using declarations: at least the function call typo will be
> > caught.
> >
> > If protection in above situations is desired, a solution would be to
> > explicitly delete the operations we don’t want:
> >
> > *Tilt& operator+=(Tilt&,Height const&) = delete;*
> >
> > This would protect against the code you suggested, but the following
> > would still be valid:
> >
> > *int h2; // “int”, not “Height”*
> >
> > *t += h2; // OK – and maybe oops, or not*
> >
> > Another solution would be to use the other suggested construct:
> >
> > *using Height = explicit int;*
> >
> > *using Tilt = explicit int;*
> >
> > *Height h{1}; // OK*
> >
> > *Tilt t{2}; // OK*
> >
> > *t += 1; // OK – literal used*
> >
> > *t += h; // ill-formed here thanks to the “explicit”*
> >
> > With the “explicit” construct, there’s no implicit interaction between
> > T and U.
> >
> > Regards,
> >
> > *Yves Bailly**
> > *Development engineer
> > Manufacturing Intelligence division
> > *Hexagon*
> > *M: *+33 (0) 6.82.66.09.01
> > HexagonMI.com
> > <https://eur02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww
> > .hexagonmi.com%2Ffr-
> FR%2F&data=04%7C01%7C%7C134ffe8c243847ad5e3e08
> >
> d8c2aeaba5%7C1b16ab3eb8f64fe39f3e2db7fe549f6a%7C0%7C0%7C6374734
> 0275077
> >
> 6770%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luM
> zIiLCJBT
> >
> iI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=hTssL%2BXeNX2jh2q0Flp
> 62KHwe
> > 8L5Tyyv1l2%2B4pm3cZQ%3D&reserved=0>
> >
> >
> >
>
>
> --
> Peter Sommerlad
>
> Better Software: Consulting, Training, Reviews Modern, Safe & Agile C++
>
> peter.cpp_at_[hidden]
> +41 79 432 23 32
As nice and well-done your framework is, it is still "yet another" approach to provide strong typing to C++.
Suppose I have created my own, and I use a library providing its own, and I use another library providing yours... Now I have at least 3 incompatible and competing "strong typing" frameworks in my software. Complexity, confusion... similar situation when you have to use geometric point types and you have to use several libraries, each providing their own ones 😊 glm::vec3 and Eigen::Vector3f are basically the same thing yet it's a pain if I have to combine them in a single algorithm, because using 3rd party libraries.
This is to illustrate my opinion that there's a real need to somehow provide a standard way to achieve the desired goal - here, strong typing.
Maybe, probably it can be done at the library level. However, a library implementation involves some more or less heavy template machinery, making it not so easy to use. Moreover it would probably increase compile time, which is usually not desirable (I daily work on softwares that typically need hours to build).
Also a library implementation implies some kind of tag to distinguish between the "strongly type types", either a value or an empty type. The management of these tags is put on the user's responsability, making it potentially difficult to avoid clashes with locally defined derived types and ones from a third party library.
That's why I thought an extension to the language would be more practical - although probably more work for compilers writers.
Regards,
Yves Bailly
Development engineer
Manufacturing Intelligence division
Hexagon
M: +33 (0) 6.82.66.09.01
HexagonMI.com
> -----Original Message-----
> From: Peter Sommerlad (C++) <peter.cpp_at_sommerlad.ch>
> Sent: Wednesday, January 27, 2021 11:31
> To: std-proposals_at_lists.isocpp.org; BAILLY Yves via Std-Proposals <std-
> proposals_at_[hidden]>
> Cc: BAILLY Yves <yves.bailly_at_hexagon.com>
> Subject: Re: [std-proposals] Explicit using --> Library for simple strong types
>
> This email is not from Hexagon’s Office 365 instance. Please be careful while
> clicking links, opening attachments, or replying to this email.
>
>
> FWIW, I created a very simple to use strong typing framework for C++17 that
> allows to create strong types with respective selection of appropriate operators
> on a single line, such as
>
> struct Word:strong<std::string,Word, Out, Add, Order>{};
>
> struct literGas:strong<double,literGas,Additive,Order,Out>{
> constexpr static inline auto suffix=" l";
> };
> the suffix static member is for output customization.
>
> Available at
> https://eur02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.c
> om%2FPeterSommerlad%2FPSsst&data=04%7C01%7C%7C134ffe8c24384
> 7ad5e3e08d8c2aeaba5%7C1b16ab3eb8f64fe39f3e2db7fe549f6a%7C0%7C0%
> 7C637473402750776770%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAw
> MDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdat
> a=TjsDb4SSwerQuv8A8%2B2SniCDv00deU3KxA7VbSbqbtI%3D&reserved=
> 0
>
> So I see little need in the language change, but I also did not follow the
> discussed details.
>
> Regards
> Peter.
>
> BAILLY Yves via Std-Proposals wrote on 27.01.21 11:22:
> > I think I get your point. After more thinking about it (which I should
> > have done before, sorry for that), then in short, I would say when
> > writing
> >
> > *using U = new T;*
> >
> > …then yes, *U* is a new type different from *T* – although referring
> > to the same Platonic type as *T*.
> >
> > This implies that indeed, *std::is_same<T,U>* is different from
> > *std::is_same<T,T>* and *std::is_same_v<T,U> == std::is_same_v<U,T> ==
> > false*.
> >
> >> For example:
> >
> >> template<class A> void f(A a);
> >
> >> f(T{}); // #1
> >
> >> f(U{}); // #2
> >
> >> Does #1 call f<T>? (Yes, it must.)
> >
> > Yes.
> >
> >> Does #2 call f<U>? (I don't know but I think so.)
> >
> > Yes, because it’s given a *U*.
> >
> >> Is f<U> the same function as, or a different function from, f<T>? (I
> >> don't know but I think so.)
> >
> > If *T* and *U* are two different types, then *f<U>* is a different
> > function from *f<T>*.
> >
> > /However,/ because *U* and *T* refer to the same Platonic type and a
> > *U* can be seen as a *T*, then if *f<U>* is syntactically correct,
> > well-formed with regard to the restrictions put on U (for example,
> > inside *f<>* there’s no assignment of a *T* to a *U* without an
> > explicit cast), then the actual instantiation of *f<U>* can be the
> > same as the instantiation of *f<T>* - in a way, *f<U> = f<T>*. Put in
> > another way, if we assume *f<T>* has already been created, then the
> > compiler would create a new “envelop” named *f<U>* but with the same
> > contents as *f<T>* – unless of course some explicit specialization
> > *f<U>* is provided by the user.
> >
> > This would apply to the *std::hash<>* specialization: when required to
> > instantiate *std::hash<U>*, if it has not been explicitly specialized,
> > then as you said the compiler may realize that *std::hash<U>* is the
> > same (has the same contents although it doesn’t have the same
> > identity) as *std::hash<T>* - again, if and only if the code for
> > *std::hash<U>* is well-formed and there’s no explicit specialization
> > defined provided by the user.
> >
> >> using Height = new int;
> >
> >> using Tilt = new int;
> >
> >> void increaseAltitude(Height h);
> >
> >> void increaseAttitude(Tilt t);
> >
> >> ...
> >
> >> Height h;
> >
> >> increaseAttitude(h); // oops — but, since increaseAttitude takes a Tilt, this
> happily won't compile!
> >
> >>
> >
> >> However, it doesn't seem to protect us against
> >
> >> Height h;
> >
> >> Tilt t;
> >
> >> t += h; // oops — and this silently calls the built-in candidate
> >>operator+=(int&, int)
> >
> > That’s true indeed, no more protection here than when using
> > “traditional” typedefs. And I see how this can indeed be seen as a
> > “massive inconsistency” between *t=h* (not OK) and *t+=h* (OK).
> >
> > However, I would argue the situation is still better than when using
> > “standard” using declarations: at least the function call typo will be
> > caught.
> >
> > If protection in above situations is desired, a solution would be to
> > explicitly delete the operations we don’t want:
> >
> > *Tilt& operator+=(Tilt&,Height const&) = delete;*
> >
> > This would protect against the code you suggested, but the following
> > would still be valid:
> >
> > *int h2; // “int”, not “Height”*
> >
> > *t += h2; // OK – and maybe oops, or not*
> >
> > Another solution would be to use the other suggested construct:
> >
> > *using Height = explicit int;*
> >
> > *using Tilt = explicit int;*
> >
> > *Height h{1}; // OK*
> >
> > *Tilt t{2}; // OK*
> >
> > *t += 1; // OK – literal used*
> >
> > *t += h; // ill-formed here thanks to the “explicit”*
> >
> > With the “explicit” construct, there’s no implicit interaction between
> > T and U.
> >
> > Regards,
> >
> > *Yves Bailly**
> > *Development engineer
> > Manufacturing Intelligence division
> > *Hexagon*
> > *M: *+33 (0) 6.82.66.09.01
> > HexagonMI.com
> > <https://eur02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww
> > .hexagonmi.com%2Ffr-
> FR%2F&data=04%7C01%7C%7C134ffe8c243847ad5e3e08
> >
> d8c2aeaba5%7C1b16ab3eb8f64fe39f3e2db7fe549f6a%7C0%7C0%7C6374734
> 0275077
> >
> 6770%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luM
> zIiLCJBT
> >
> iI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=hTssL%2BXeNX2jh2q0Flp
> 62KHwe
> > 8L5Tyyv1l2%2B4pm3cZQ%3D&reserved=0>
> >
> >
> >
>
>
> --
> Peter Sommerlad
>
> Better Software: Consulting, Training, Reviews Modern, Safe & Agile C++
>
> peter.cpp_at_[hidden]
> +41 79 432 23 32
Received on 2021-01-27 04:51:10