Topic: Strongly Types / Opaque Types library
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sat, 31 Dec 2016 18:19:48 +0100
Raw View
This is a multi-part message in MIME format.
--------------E4887C3B61908238FE6C1813
Content-Type: text/plain; charset=UTF-8; format=flowed
Hi,
I would like to have some feedback about the approach I've taken in an
old prototype TBoost.Opaque [1]. This is not ready for a C++ standard
proposal (The interface is C++98 based). TBoost.Opaque is a library
solution to the problem presented in [0].
The idea behind strongly types is to define a new type based on an
existing type (its underlying type) and define the operations that can
be applied to this new type in as simple as possible way.
There are several decisions while defining a strong type as several
proposals have already described:
* convertibility: is the new type convertible (explicit/implicitly)
to/from the underlying type?
* do we want to inherit from the underlying type some operations by default?
* if, yes,
* which operations are inherited by default from the underlying type?
* how to hide operations inherited by default?
* if not,
* how to add new operations that just do conversions to and from
the underlying type?
* how to add a group of operations that are seen as a whole?
* do we want to be able to add more data members?
Any new type is at least explicitly convertible from its underlying type.
Boost.Opaque tries to answer to all these questions using a meta-mixin
concept and stacking mixins to build the new type from the underlying
type (using CRTP on a linear hierarchy).
For example. we can define an Identifier that can be used in a map using
an underlying type int as follows
using Identifier = opaque::new_type< int, struct IdentifierTag,
opaque::derives< opaque::using_totally_ordered >
>;
This new type will have the same size as its underlying int type and
will provide the total order operations based on the ones provided by
the underlying type. This type will not be convertible to int and no
other operations are provided. struct IdentifierTag is used as a tag
making the type different.
The opaque::derives contains the sequence of meta-mixins that will be
part of the inherited
The library defines meta-mixing for each operator and meta-mixing for
some concepts we can derive from, es e;g. totally_ordered. The idea is
similar to boost:operators but instead of introducing operations that
depend on another operation, it introduce operations based on operations
on the underlying type.
Next follows some concepts used in the library:
Classes that models the |Final| concept satisfy the following expressions:
Let |B| a base class of |Final|, |b| an instance of |B|, |bc| an
instance of |B const|.
* |Final::final(&b)| return the |Final&| reference associated to |b|.
* |Final::final(&bc)| returns the |const Final&| reference associated
to |bc|.
Classes that models the |FinalUnderlying| concept satisfy the following
expressions:
Let |B| a base class of |Final|, |b| an instance of |B|, |bc| an
instance of |B const|, |f| an instace of |Final| and |fc| and instance
of `Final const '.
* |Final::underlying_type| the underlying type.
* |Final::underlying(&b)| return a reference to
|Final::underlying_type&| associated to |b|.
* |Final::underlying(&bc)| return a constant reference to
|Final::underlying_type const&| associated to |bc|.
* |f.underlying()| return a reference to |Final::underlying_type&|
associated to |f|.
* |fc.underlying()| return a constant reference to
|Final::underlying_type const&| associated to |fc|.
A Mixin is a template class having two template parameters, the Final
type and the Base type.
The archetype of a Mixin is
template <typename Final, typename Base>
struct MixinArchetype : Base
{
...
};
A MetaMixin is a meta-function having as nested type a Mixin. The
archetype of a MetaMixin is
struct MetaMixinArchetype {
template <typename Final, typename Base>
struct type : Base
{
...
};
};
Associated to a type there is a meta-mixin that states the default
operations inherited (inherited_from_underlying). This meta-mixin is a
customization point and can be used while defining a new type based on
a underlying type. We can define then a new strongly int class as follows
using GameScore = opaque::new_type< int, struct GameScoreTag,
opaque::derives< opaque::inherited_from_underlying >
>;
In addition to aliases we can define classes as e.g. the Energy from p0109r0
class Energy : public opaque::new_class< Energy, double,
opaque::derives<
opaque::using_additive,
opaque::using_multipliative_with<double>
>
> {
using base_type = opaque::new_class< Energy, double,
opaque::derives<
opaque::using_additive,
opaque::using_multipliative_with<double>
>;
public:
using base_type::base::type;
void print();
};
this will be the equivalent to the p0109r0 [2] opaque type
using energy = protected double {
// additive/addable
friend energy operator+ (energy) = default;
friend energy operator+ (energy , energy) = default;
friend energy operator+= (energy& , energy) = default;
// additive/ |subtractable|
friend energy operator- (energy) = default;
friend energy operator- (energy , energy) = default;
friend energy operator-= (energy& , energy) = default;
// multipliative_with<double>
friend energy& operator*=(energy&, double) = default;
friend energy operator* (energy , double) = default;
friend energy operator* (double , energy) = default;
friend energy& operator/=(energy&, double) = default;
friend energy operator/ (energy , double) = default;
void print();
};
Having a way to name the base class will reduce the syntactic noise
class Energy : public *using base_type = *opaque::new_class< Energy,
double,
opaque::derives<
opaque::using_additive,
opaque::using_multipliative_with<double>
>
> {
public:
using base_type::base::type;
void print();
};
Comments welcome,
Vicente
[0] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2141.html
[1]
https://htmlpreview.github.io/?https://github.com/viboes/opaque/blob/master/libs/opaque/doc/html/index.html
[2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0109r0.pdf
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/d2160ffc-c6bf-6212-2b9c-b589b407ed50%40wanadoo.fr.
--------------E4887C3B61908238FE6C1813
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"content-type" content=3D"text/html; charset=3Dutf-8=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
Hi,<br>
<br>
<br>
I would like to have some feedback about the approach I've taken in
an old prototype TBoost.Opaque [1]. This is not ready for a C++
standard proposal (The interface is C++98 based). TBoost.Opaque is a
library solution to the problem presented in=C2=A0 [0].<br>
<br>
The idea behind strongly types is to define a new type based on an
existing type (its underlying type) and define the operations that
can be applied to this new type in as simple as possible way.<br>
<br>
There are several decisions while defining a strong type as several
proposals have already described:<br>
* convertibility: is the new type convertible (explicit/implicitly)
to/from the underlying type?<br>
* do we want to inherit from the underlying type some operations by
default?<br>
* if, yes, <br>
=C2=A0=C2=A0=C2=A0 * which operations are inherited by default from the=
underlying
type?<br>
=C2=A0=C2=A0=C2=A0 * how to hide operations inherited by default?<br>
* if not, <br>
=C2=A0=C2=A0=C2=A0 * how to add new operations that just do conversions=
to and from
the underlying type?<br>
=C2=A0=C2=A0=C2=A0 * how to add a group of operations that are seen as =
a whole?<br>
* do we want to be able to add more data members?<br>
<br>
Any new type is at least explicitly convertible from its underlying
type.<br>
<br>
Boost.Opaque tries to answer to all these questions using a
meta-mixin concept and stacking mixins to build the new type from
the underlying type (using CRTP on a linear hierarchy).<br>
<br>
For example. we can define an Identifier that can be used in a map
using an underlying type int as follows<br>
<br>
=C2=A0=C2=A0=C2=A0 using Identifier =3D opaque::new_type< int, struc=
t
IdentifierTag,<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 opaque::derives< opaque::using=
_totally_ordered ><br>
=C2=A0=C2=A0=C2=A0 >;<br>
<br>
<br>
This new type will have the same size as its underlying int type and
will provide the total order operations based on the ones provided
by the underlying type. This type will not be convertible to int and
no other operations are provided.=C2=A0 struct IdentifierTag is used as=
a
tag making the type different.<br>
The opaque::derives contains the sequence of meta-mixins that will
be part of the inherited <br>
The library defines meta-mixing for each operator and meta-mixing
for some concepts we can derive from, es e;g. totally_ordered. The
idea is similar to boost:operators but instead of introducing
operations that depend on another operation, it introduce operations
based on operations on the underlying type.<br>
<br>
<br>
Next follows some concepts used in the library:<br>
<p>Classes that models the <code class=3D"computeroutput"><span
class=3D"identifier">Final</span></code> concept satisfy the
following expressions: </p>
<p> Let <code class=3D"computeroutput"><span class=3D"identifier">B</sp=
an></code>
a base class of <code class=3D"computeroutput"><span
class=3D"identifier">Final</span></code>, <code
class=3D"computeroutput"><span class=3D"identifier">b</span></code>
an instance of <code class=3D"computeroutput"><span
class=3D"identifier">B</span></code>, <code
class=3D"computeroutput"><span class=3D"identifier">bc</span></code=
>
an instance of <code class=3D"computeroutput"><span
class=3D"identifier">B</span> <span class=3D"keyword">const</span=
></code>.
</p>
<div class=3D"itemizedlist">
<ul class=3D"itemizedlist" type=3D"disc">
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">final</span><span class=3D"special">(&am=
p;</span><span
class=3D"identifier">b</span><span class=3D"special">)</span>=
</code>
return the <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">&=
;</span></code>
reference associated to <code class=3D"computeroutput"><span
class=3D"identifier">b</span></code>. </li>
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">final</span><span class=3D"special">(&am=
p;</span><span
class=3D"identifier">bc</span><span class=3D"special">)</span=
></code>
returns the <code class=3D"computeroutput"><span
class=3D"keyword">const</span> <span class=3D"identifier">Fin=
al</span><span
class=3D"special">&</span></code> reference associated
to <code class=3D"computeroutput"><span class=3D"identifier">bc</=
span></code>.
</li>
</ul>
</div>
<p> Classes that models the <code class=3D"computeroutput"><span
class=3D"identifier">FinalUnderlying</span></code> concept
satisfy the following expressions: </p>
<p> Let <code class=3D"computeroutput"><span class=3D"identifier">B</sp=
an></code>
a base class of <code class=3D"computeroutput"><span
class=3D"identifier">Final</span></code>, <code
class=3D"computeroutput"><span class=3D"identifier">b</span></code>
an instance of <code class=3D"computeroutput"><span
class=3D"identifier">B</span></code>, <code
class=3D"computeroutput"><span class=3D"identifier">bc</span></code=
>
an instance of <code class=3D"computeroutput"><span
class=3D"identifier">B</span> <span class=3D"keyword">const</span=
></code>,
<code class=3D"computeroutput"><span class=3D"identifier">f</span></c=
ode>
an instace of <code class=3D"computeroutput"><span
class=3D"identifier">Final</span></code> and <code
class=3D"computeroutput"><span class=3D"identifier">fc</span></code=
>
and instance of `Final const '. </p>
<div class=3D"itemizedlist">
<ul class=3D"itemizedlist" type=3D"disc">
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying_type</span></code> the
underlying type. </li>
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying</span><span class=3D"special"=
>(&</span><span
class=3D"identifier">b</span><span class=3D"special">)</span>=
</code>
return a reference to <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying_type</span><span
class=3D"special">&</span></code> associated to <code
class=3D"computeroutput"><span class=3D"identifier">b</span></c=
ode>.
</li>
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying</span><span class=3D"special"=
>(&</span><span
class=3D"identifier">bc</span><span class=3D"special">)</span=
></code>
return a constant reference to <code class=3D"computeroutput"><sp=
an
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying_type</span> <span
class=3D"keyword">const</span><span class=3D"special">&</=
span></code>
associated to <code class=3D"computeroutput"><span
class=3D"identifier">bc</span></code>. </li>
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">f</span><span class=3D"special">.</span>=
<span
class=3D"identifier">underlying</span><span class=3D"special"=
>()</span></code>
return a reference to <code class=3D"computeroutput"><span
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying_type</span><span
class=3D"special">&</span></code> associated to <code
class=3D"computeroutput"><span class=3D"identifier">f</span></c=
ode>.
</li>
<li class=3D"listitem"> <code class=3D"computeroutput"><span
class=3D"identifier">fc</span><span class=3D"special">.</span=
><span
class=3D"identifier">underlying</span><span class=3D"special"=
>()</span></code>
return a constant reference to <code class=3D"computeroutput"><sp=
an
class=3D"identifier">Final</span><span class=3D"special">::</=
span><span
class=3D"identifier">underlying_type</span> <span
class=3D"keyword">const</span><span class=3D"special">&</=
span></code>
associated to <code class=3D"computeroutput"><span
class=3D"identifier">fc</span></code>. </li>
</ul>
</div>
<p> A Mixin is a template class having two template parameters, the
Final type and the Base type. </p>
<p> The archetype of a Mixin is </p>
<pre class=3D"programlisting"><span class=3D"keyword">template</span> <=
span class=3D"special"><</span><span class=3D"keyword">typename</span> <=
span class=3D"identifier">Final</span><span class=3D"special">,</span> <spa=
n class=3D"keyword">typename</span> <span class=3D"identifier">Base</span><=
span class=3D"special">></span>
<span class=3D"keyword">struct</span> <span class=3D"identifier">MixinArche=
type</span> <span class=3D"special">:</span> <span class=3D"identifier">Bas=
e</span>
<span class=3D"special">{</span>
<span class=3D"special">...</span>
<span class=3D"special">};</span>
</pre>
<br>
<p> A MetaMixin is a meta-function having as nested type a Mixin.
The archetype of a MetaMixin is </p>
<pre class=3D"programlisting"><span class=3D"keyword">struct</span> <sp=
an class=3D"identifier">MetaMixinArchetype</span> <span class=3D"special">{=
</span>
<span class=3D"keyword">template</span> <span class=3D"special"><</s=
pan><span class=3D"keyword">typename</span> <span class=3D"identifier">Fina=
l</span><span class=3D"special">,</span> <span class=3D"keyword">typename</=
span> <span class=3D"identifier">Base</span><span class=3D"special">></s=
pan>
<span class=3D"keyword">struct</span> <span class=3D"identifier">type</=
span> <span class=3D"special">:</span> <span class=3D"identifier">Base</spa=
n>
<span class=3D"special">{</span>
<span class=3D"special">...</span>
<span class=3D"special">};</span>
<span class=3D"special">};</span>
</pre>
<br>
<br>
<br>
Associated to a type there is a meta-mixin that states the default
operations inherited (inherited_from_underlying). This meta-mixin is
a customization point and can be used=C2=A0 while defining a new type
based on a underlying type. We can define then a new strongly int
class as follows<br>
<br>
=C2=A0=C2=A0=C2=A0 using GameScore =3D opaque::new_type< int, struct=
GameScoreTag,<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 opaque::derives< opaque::inher=
ited_from_underlying ><br>
=C2=A0=C2=A0=C2=A0 >;<br>
<br>
In addition to aliases we can define classes as e.g. the Energy from
p0109r0<br>
<br>
<br>
class Energy : public opaque::new_class< Energy, double, <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0opaque::derive=
s< <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0 opaque::using_additive, <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0 opaque::using_multipliative_with<double> <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 ><br>
> {<br>
=C2=A0=C2=A0 =C2=A0using base_type =3D opaque::new_class< Energy, do=
uble, <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0opaque::derive=
s< <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0 opaque::using_additive, <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0 opaque::using_multipliative_with<double> <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 >;<br>
public:<br>
=C2=A0=C2=A0 =C2=A0using base_type::base::type;<br>
=C2=A0=C2=A0=C2=A0 void print();<br>
};<br>
<br>
<br>
this will be the equivalent to the p0109r0 [2] opaque type<br>
<br>
using energy =3D protected double {<br>
=C2=A0=C2=A0=C2=A0 // additive/addable<br>
=C2=A0=C2=A0=C2=A0 friend energy operator+ (energy) =3D default;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator+ (energy , energy) =3D defaul=
t;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator+=3D (energy& , energy) =
=3D default;<br>
=C2=A0=C2=A0=C2=A0 // additive/
<meta http-equiv=3D"content-type" content=3D"text/html; charset=3Dutf-8=
">
<code class=3D"computeroutput"><span class=3D"identifier">subtractable<=
/span></code><br>
=C2=A0=C2=A0=C2=A0 friend energy operator- (energy) =3D default;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator- (energy , energy) =3D defaul=
t;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator-=3D (energy& , energy) =
=3D default;<br>
<br>
=C2=A0=C2=A0=C2=A0 // multipliative_with<double><br>
=C2=A0=C2=A0=C2=A0 friend energy& operator*=3D(energy&, double)=
=3D default;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator* (energy , double) =3D defaul=
t;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator* (double , energy) =3D defaul=
t;<br>
=C2=A0=C2=A0=C2=A0 friend energy& operator/=3D(energy&, double)=
=3D default;<br>
=C2=A0=C2=A0=C2=A0 friend energy operator/ (energy , double) =3D defaul=
t;<br>
<br>
=C2=A0=C2=A0=C2=A0 void print();<br>
};<br>
<br>
<br>
Having a way to name the base class will reduce the syntactic noise<br>
<br>
class Energy : public <b>using base_type =3D </b>opaque::new_class<
Energy, double, <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0opaque::derive=
s< <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0 opaque::using_additive, <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0 opaque::using_multipliative_with<double> <br>
=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 ><br>
> {<br>
public:<br>
=C2=A0=C2=A0 =C2=A0using base_type::base::type;<br>
=C2=A0=C2=A0=C2=A0 void print();<br>
};<br>
<br>
Comments welcome,<br>
Vicente<br>
<br>
[0]
<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/jtc1=
/sc22/wg21/docs/papers/2006/n2141.html">http://www.open-std.org/jtc1/sc22/w=
g21/docs/papers/2006/n2141.html</a><br>
[1]
<a class=3D"moz-txt-link-freetext" href=3D"https://htmlpreview.github.io/?h=
ttps://github.com/viboes/opaque/blob/master/libs/opaque/doc/html/index.html=
">https://htmlpreview.github.io/?https://github.com/viboes/opaque/blob/mast=
er/libs/opaque/doc/html/index.html</a><br>
[2]
<a class=3D"moz-txt-link-freetext" href=3D"http://www.open-std.org/jtc1=
/sc22/wg21/docs/papers/2015/p0109r0.pdf">http://www.open-std.org/jtc1/sc22/=
wg21/docs/papers/2015/p0109r0.pdf</a><br>
<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/d2160ffc-c6bf-6212-2b9c-b589b407ed50%=
40wanadoo.fr?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d2160ffc-c6bf-6212-2b9c-b589b407ed50=
%40wanadoo.fr</a>.<br />
--------------E4887C3B61908238FE6C1813--
.