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&lt; int, struc=
t
    IdentifierTag,<br>
    =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 opaque::derives&lt; opaque::using=
_totally_ordered &gt;<br>
    =C2=A0=C2=A0=C2=A0 &gt;;<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">&amp=
;</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">&amp;</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"=
>(&amp;</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">&amp;</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"=
>(&amp;</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">&amp;</=
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">&amp;</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">&amp;</=
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">&lt;</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">&gt;</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">&lt;</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">&gt;</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&lt; int, struct=
 GameScoreTag,<br>
    =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 opaque::derives&lt; opaque::inher=
ited_from_underlying &gt;<br>
    =C2=A0=C2=A0=C2=A0 &gt;;<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&lt; Energy, double, <br>
    =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0opaque::derive=
s&lt; <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&lt;double&gt; <br>
    =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 &gt;<br>
    &gt; {<br>
    =C2=A0=C2=A0 =C2=A0using base_type =3D opaque::new_class&lt; Energy, do=
uble, <br>
    =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0opaque::derive=
s&lt; <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&lt;double&gt; <br>
    =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 &gt;;<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&amp; , 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&amp; , energy) =
=3D default;<br>
    <br>
    =C2=A0=C2=A0=C2=A0 // multipliative_with&lt;double&gt;<br>
    =C2=A0=C2=A0=C2=A0 friend energy&amp; operator*=3D(energy&amp;, 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&amp; operator/=3D(energy&amp;, 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&lt;
    Energy, double, <br>
    =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0opaque::derive=
s&lt; <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&lt;double&gt; <br>
    =C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 &gt;<br>
    &gt; {<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&quot; 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--

.