Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make custom struct's constructors in C++ consistent with the rest of code. #548

Open
Hsilgos opened this issue Oct 20, 2020 · 1 comment
Labels
c++ enhancement New feature or request

Comments

@Hsilgos
Copy link
Contributor

Hsilgos commented Oct 20, 2020

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:

  1. Move custom factory methods 'make' to private sections
  2. Call factory methods in public constructors in the same way as Swift/Java does
  3. 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.

@DanielKamkha DanielKamkha added the enhancement New feature or request label Feb 26, 2021
@DanielKamkha DanielKamkha self-assigned this Feb 26, 2021
@DanielKamkha DanielKamkha removed their assignment Mar 1, 2021
@DanielKamkha
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants