[core] Determining interest for two new classes: readonly and newtype

Hey, I have two classes I've developed that have been used in my own projects that I think could have a place in Boost. They are outlined below. readonly<T>: This is a wrapper class for a type to replace a const-type field in a movable class. It has const access to the type so can't modify except for the move constructor and move assignment operator. This solves the problem that no fields in a movable class can be const which can cloud the intentions of a field. readonly copies the accessor patterns seen in classes such as optional and the smart pointer collection. Example: struct foo { foo() : str("hello world") {} readonly<std::string> str; }; foo f; auto g = std::move(f); static_assert(std::is_move_constructible<foo>{}, ""); std::cout << *g.str << std::endl; g.str->clear() // error: non-const method. ----- newtype<N, T> This is shamelessly ripped off from Haskell and provides strongly-typed typedefs to C++. It actually has two template parameters, one is an incomplete type that provides a unique identifier for this typedef. I've opted to use the name of the typedef with an '_t' suffix, the second is the raw type that it contains. Like readonly the underlying type can be accessed by operator*, operator-> and get() methods. Example: using age = newtype<struct age_t, int>; age a{25}; using byte = newtype<struct byte_t, int>; byte b{42}; // do something with bytes (*not* any old int). void bar(const byte); bar(a); // error: wrong type wanted 'byte' got 'age' bar(b); // okay bar(89); // error: wrong type wanted 'byte' got 'int' assert(*b == 42); Any thoughts on the design and/or their place in Boost would be much appreciated. Cheers, Sam

On 8/16/15 7:23 AM, Sam Kellett wrote:
Hey, I have two classes I've developed that have been used in my own projects that I think could have a place in Boost. They are outlined below.
readonly<T>:
newtype<N, T>
Interesting ideas. Do you want to prepare them as boost like libraries - ie, with source code repository, documentation, tests and examples ? If so, you might want to consult www.blincubator.com on how to do this. Robert Ramey

Robert wrote:
Interesting ideas. Do you want to prepare them as boost like libraries - ie, with source code repository, documentation, tests and examples ?
I think his intention was to add them to Boost.Core in the same fashion as ignore_used() and other similar small utilities (recently enable_if_has_type). Glen

Robert wrote:
Interesting ideas. Do you want to prepare them as boost like libraries - ie, with source code repository, documentation, tests and examples ?
I think his intention was to add them to Boost.Core in the same fashion as ignore_used() and other similar small utilities (recently enable_if_has_type).
yeah, they didn't seem to hold enough substance to warrant their own libraries (nor are they that correlated to share one between them).

Den 16-08-2015 kl. 22:46 skrev Sam Kellett:
Robert wrote:
Interesting ideas. Do you want to prepare them as boost like libraries - ie, with source code repository, documentation, tests and examples ?
I think his intention was to add them to Boost.Core in the same fashion as ignore_used() and other similar small utilities (recently enable_if_has_type).
yeah, they didn't seem to hold enough substance to warrant their own libraries (nor are they that correlated to share one between them).
Neither argument above precludes using the incubator, nor having a review. Regards, Brian

readonly<T>:
This is a wrapper class for a type to replace a const-type field in a movable class. It has const access to the type so can't modify except for the move constructor and move assignment operator.
This solves the problem that no fields in a movable class can be const which can cloud the intentions of a field.
This reminded me of something I hit recently: I wanted to have a bunch of fields to be const, but in one constructor I needed to initialize them in the constructor body, not in the initializer list. This created two problems. I thought I might be able to get around the first (of how to actually set them) by using casts; the second problem was the compiler warnings that I was not initializing all const members. I couldn't work that one out, so I gave up and removed const from all of them. Would your readonly<T> have helped me here? (And, conversely, if it could, that implies the compiler cannot warn when they are not initialized?) Darren

This reminded me of something I hit recently: I wanted to have a bunch of fields to be const, but in one constructor I needed to initialize them in the constructor body, not in the initializer list.
This created two problems. I thought I might be able to get around the first (of how to actually set them) by using casts; the second problem was the compiler warnings that I was not initializing all const members. I couldn't work that one out, so I gave up and removed const from all of them.
this is one of the main disadvantages (and discrepancy's against constness) as you do not get a compiler error if your readonly variable is not in your initializer list like you would with a const field.
Would your readonly<T> have helped me here? (And, conversely, if it could, that implies the compiler cannot warn when they are not initialized?)
if i understand correctly i don't think readonly would help you here as readonly, like const-fields can only be set at construction, so in the initializer list. you would not be able to call any non-const methods on your field in the constructor's body.

Sam Kellett wrote:
Hey, I have two classes I've developed that have been used in my own projects that I think could have a place in Boost. They are outlined below.
readonly<T>:
This is a wrapper class for a type to replace a const-type field in a movable class. It has const access to the type so can't modify except for the move constructor and move assignment operator.
...
newtype<N, T>
This is shamelessly ripped off from Haskell and provides strongly-typed typedefs to C++.
These look interesting and useful. I do not think they belong in [core] though, which is for components that are used throughout Boost. [utility] seems a better place.

These look interesting and useful. I do not think they belong in [core] though, which is for components that are used throughout Boost. [utility] seems a better place.
thanks! yeah utility would also work, i looked there first actually but saw that quite a few of it's contents had been moved to Boost.Core so i figured that core was the more recent iteration of the same idea of a collection of small classes. my mistake!

Le 16/08/15 16:23, Sam Kellett a écrit :
Hey, I have two classes I've developed that have been used in my own projects that I think could have a place in Boost. They are outlined below.
readonly<T>:
This is a wrapper class for a type to replace a const-type field in a movable class. It has const access to the type so can't modify except for the move constructor and move assignment operator.
This solves the problem that no fields in a movable class can be const which can cloud the intentions of a field.
readonly copies the accessor patterns seen in classes such as optional and the smart pointer collection.
Example:
struct foo { foo() : str("hello world") {}
readonly<std::string> str; };
foo f; auto g = std::move(f);
static_assert(std::is_move_constructible<foo>{}, "");
std::cout << *g.str << std::endl; g.str->clear() // error: non-const method. How is this relatedto this proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html
-----
newtype<N, T>
This is shamelessly ripped off from Haskell and provides strongly-typed typedefs to C++.
It actually has two template parameters, one is an incomplete type that provides a unique identifier for this typedef. I've opted to use the name of the typedef with an '_t' suffix, the second is the raw type that it contains.
Like readonly the underlying type can be accessed by operator*, operator-> and get() methods.
Example:
using age = newtype<struct age_t, int>; age a{25};
using byte = newtype<struct byte_t, int>;2] byte b{42};
// do something with bytes (*not* any old int). void bar(const byte);
bar(a); // error: wrong type wanted 'byte' got 'age' bar(b); // okay bar(89); // error: wrong type wanted 'byte' got 'int'
assert(*b == 42);
Any thoughts on the design and/or their place in Boost would be much appreciated.
You could take a look at the proposal for Opaque types [1]. I would be grateful if you can tell me what do you think of a prototype I started longtime ago [2]. Please, note that it is not my intention to discourage you with your proposal, as the scope of your class much simpler. Best, Vicente [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf [2] https://htmlpreview.github.io/?https://github.com/viboes/opaque/blob/master/... https://github.com/viboes/opaque

readonly<T>:
[snip]
How is this relatedto this proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html
if i understand correctly that is about getting fields that are pointers to respect the const-ness of the object they belong in. so, struct foo { std::string *s; }; const foo f; f.s->clear() // even though f is const i can still call a non-const method on one of it's members. whereas readonly simply provides a guard against non-const methods on the field itself (so, the pointer, not the pointee if you were to use it for the above struct) without making the field actually const (so as to still allow moving). struct foo { readonly<std::string *> s; }; const foo f; f.s*->clear(); // will still work, it's only the pointer that is now immutable. nb: *-> may or may not be required here, writing this straight into the email and am not 100% that that is correct..
-----
newtype<N, T>
[snip]
You could take a look at the proposal for Opaque types [1].
this is nice. definitely solves the same problem. do you have any idea on the status of that paper? the link is 2013, but i know that doesn't mean much.. is it c++17 expected or later (or ever, atm)?
I would be grateful if you can tell me what do you think of a prototype I started longtime ago [2]. Please, note that it is not my intention to discourage you with your proposal, as the scope of your class much simpler.
this is nice too, i played around with the idea of allowing certain traits of types to propagate through newtype (ala Haskell's deriving statement) but opted on the simplicity side just for my use case. if i wanted a set of newtype<struct foo, int>'s i would simply define a overload for > for that typedef. i didn't want to do it by default as it's presumptious to assume any type that is represented by an integer would be orderable, but some sort of solution that allows you to pass in a list of additions like you had could form a proper general solution. using byte = newtype<struct byte_t, int, deriving<typeclass::show, typeclass::eq, typeclass::ord>>; std::cout << byte{10} << std::endl; // show assert(byte{10} == byte{10}); // eq using byte_set = std::set<byte>; // ord that could be quite nice and something i would be happy to look into as part of the move towards boostifying these classes, should people think they have a place here.

On 18 August 2015 at 00:31, Sam Kellett <samkellett@gmail.com> wrote:
You could take a look at the proposal for Opaque types [1].
this is nice. definitely solves the same problem. do you have any idea on the status of that paper? the link is 2013, but i know that doesn't mean much.. is it c++17 expected or later (or ever, atm)?
I did some research while reading this discussion: - N3515 was updated as N3747 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3741.pdf - Both were reviewed in the Chicago meeting in 2013, see item 52 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4206.html#52 "author encouraged to pursue the idea further with revised papers." - There is no public trace from any related paper since then (that I could find). The author seem to be focused on a lot of different subjects, for example search for Walter Brown in this page (2015 papers so far) : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/ So he might have stopped improving the proposal to focus on these. Maybe you could see with Walter Brown if he did some more unpublished work on this subject.

readonly<T>:
[snip]
How is this relatedto this proposal
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html
if i understand correctly that is about getting fields that are pointers to respect the const-ness of the object they belong in. so,
struct foo { std::string *s; };
const foo f; f.s->clear() // even though f is const i can still call a non-const method on one of it's members.
whereas readonly simply provides a guard against non-const methods on the field itself (so, the pointer, not the pointee if you were to use it for the above struct) without making the field actually const (so as to still allow moving).
struct foo { readonly<std::string *> s; };
const foo f; f.s*->clear(); // will still work, it's only the pointer that is now immutable.
nb: *-> may or may not be required here, writing this straight into the email and am not 100% that that is correct.. How both wrappers could work together?
-----
newtype<N, T>
[snip]
You could take a look at the proposal for Opaque types [1]. this is nice. definitely solves the same problem. do you have any idea on the status of that paper? the link is 2013, but i know that doesn't mean much.. is it c++17 expected or later (or ever, atm)? See Joel response. I suspect that the last question depends on the work
Le 18/08/15 00:31, Sam Kellett a écrit : the author is able to do. Any comments about implicit/explicit conversion from/to the opaque type and the underlying type? Does your class support some of them?
I would be grateful if you can tell me what do you think of a prototype I started longtime ago [2]. Please, note that it is not my intention to discourage you with your proposal, as the scope of your class much simpler.
this is nice too, i played around with the idea of allowing certain traits of types to propagate through newtype (ala Haskell's deriving statement) but opted on the simplicity side just for my use case. if i wanted a set of newtype<struct foo, int>'s i would simply define a overload for > for that typedef.
i didn't want to do it by default as it's presumptious to assume any type that is represented by an integer would be orderable, but some sort of solution that allows you to pass in a list of additions like you had could form a proper general solution.
using byte = newtype<struct byte_t, int, deriving<typeclass::show, typeclass::eq, typeclass::ord>>;
std::cout << byte{10} << std::endl; // show assert(byte{10} == byte{10}); // eq using byte_set = std::set<byte>; // ord
that could be quite nice and something i would be happy to look into as part of the move towards boostifying these classes, should people think they have a place here.
Note that you could also add them conditionally (SFINAE). Count with my help if you decide to go on. Best, Vicente

On 18 August 2015 at 07:57, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 18/08/15 00:31, Sam Kellett a écrit :
readonly<T>:
[snip]
How both wrappers could work together?
i would envision that they should be fine. as readonly is a swapper for const i would do something like this: readonly<std::propagate_const<std::string *>> s; would require testing to make sure that the functionality remains though.
-----
newtype<N, T>
[snip]
You could take a look at the proposal for Opaque types [1].
this is nice. definitely solves the same problem. do you have any idea on the status of that paper? the link is 2013, but i know that doesn't mean much.. is it c++17 expected or later (or ever, atm)?
See Joel response. I suspect that the last question depends on the work the author is able to do.
Any comments about implicit/explicit conversion from/to the opaque type and the underlying type? Does your class support some of them?
it's explicit conversion only, either by casting or dereferencing. the emphasis is very strict on explicitness as this aims to solve the problem of accidentally passing, say, a height as a weight or whatever.
[snip]
that could be quite nice and something i would be happy to look into as
part of the move towards boostifying these classes, should people think they have a place here.
Note that you could also add them conditionally (SFINAE).
i'm sorry i'm not sure i follow -- could you elaborate a bit?
Count with my help if you decide to go on.
thanks! i really appreciate it. do you think this should be an extension to core/utlity? and if so what is the process for that, i know a new library should be incubated and reviewed, but is that true for extending an existing library too?

Sam wrote:
and if so what is the process for that, i know a new library should be incubated and reviewed, but is that true for extending an existing library too?
To contribute to an existing library, it is up to the maintainer of that library. There isn't a formal review process around it (unless the maintainer of that library initiates one). Best, Glen -- View this message in context: http://boost.2283326.n4.nabble.com/core-Determining-interest-for-two-new-cla... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 18 August 2015 at 23:56, Glen Fernandes <glen.fernandes@gmail.com> wrote:
Sam wrote:
and if so what is the process for that, i know a new library should be incubated and reviewed, but is that true for extending an existing library too?
To contribute to an existing library, it is up to the maintainer of that library. There isn't a formal review process around it (unless the maintainer of that library initiates one).
thanks, a quick check at the trac lists peter as the maintainer of core (and he's stated that he doesn't thing this is the correct place for these classes), and no maintainer for utility.. does that mean utility is maintained by the community maintenance team?

Sam wrote:
thanks, a quick check at the trac lists peter as the maintainer of core (and he's stated that he doesn't thing this is the correct place for these classes), and no maintainer for utility.. does that mean utility is maintained by the community maintenance team?
Feels like utility's maintainer was a community long before the CMT's existence. :-) https://github.com/boostorg/utility/blob/master/meta/libraries.json As for Core, yes:
Boost.Core, part of collection of the Boost C++ Libraries, is a collection of core utilities used by other Boost libraries. The criteria for inclusion is that the utility component be: - simple, - used by other Boost libraries, and - not dependent on any other Boost modules except Core itself, Config, Assert, Static Assert, or Predef.
Glen
participants (8)
-
Brian Ravnsgaard Riis
-
Darren Cook
-
Glen Fernandes
-
Klaim - Joël Lamotte
-
Peter Dimov
-
Robert Ramey
-
Sam Kellett
-
Vicente J. Botet Escriba