gluecodium
gluecodium copied to clipboard
Make custom struct's constructors in C++ consistent with the rest of code.
Consider next struct in lime:
struct Foo {
field1: String
field2: String = "predefined"
constructor make(field1: String)
constructor make(field1: String, field2: String)
}
Custom constructors should check parameters or fill fields by non-trivial logic. When generated code in Swift or Java contains only two constructors in this case. But C++ looks like this:
struct Foo {
::std::string field1;
::std::string field2 = "predefined";
Foo( );
Foo( ::std::string field1 );
Foo( ::std::string field1, ::std::string field2 );
static Foo make( const ::std::string& field1 );
static Foo make( const ::std::string& field1, ::std::string field2 );
};
In C++ correct way is to use factory methods like Foo::make(...)
, but it's still possible to create instance with constructors and avoid parameters checking or custom logic.
My idea is to make C++ consistent with Java/Swift in next way:
- Move custom factory methods 'make' to private sections
- Call factory methods in public constructors in the same way as Swift/Java does
- Generate constructor(s) in private section which should be called from factory methods:
struct Foo {
::std::string field1;
::std::string field2 = "predefined";
// No default Foo() ctor since it's not described in lime
Foo( ::std::string field1 );
Foo( ::std::string field1, ::std::string field2 );
private:
enum Custom {
Constructor
};
Foo( Custom );
Foo( Custom, ::std::string field1);
Foo( Custom, ::std::string field1, ::std::string field2 );
static Foo make( const ::std::string& field1 );
static Foo make( const ::std::string& field1, ::std::string field2 );
};
So, private constructors must be the same as currently generated. Public constructors must look like
Foo::Foo( ::std::string field1 ) : Foo(make(std::move(field1))) {}
Foo::Foo( ::std::string field1, ::std::string field1 ) : Foo(make(std::move(field1), std::move(field2))) {}
Custom factory methods should create structs only with private constructors:
Foo Foo::make(::std::string field1) {
return Foo(Foo::Custom::Constructor, field1, "some-custom-value");
}
Note: It's breaking change since existing code may produce infinite recursion calls, so may be it should be temporary optional behaviour with warning about deprecation.
When we're converting structs from platform to C++ we need to initialize them somehow. Right now it's done in two ways:
- with default ctor and field assignment for mutable structs
- with all-args ctor for immutable structs. Can be changed to always use all-args ctor. But there is no way to do it for a struct with a custom constructor if we hide all non-custom constructors, as per the proposal.