Papierkorb / bindgen

Binding and wrapper generator for C/C++ libraries
GNU General Public License v3.0
179 stars 18 forks source link

Aggregate constructors for wrapper classes #99

Closed HertzDevil closed 3 years ago

HertzDevil commented 3 years ago

With this PR, wrapper classes of aggregate types may be created using a familiar record syntax, like lib structs:

struct Point3D {
  int x, y, z;
};
class Point3D
  def initialize(*, x : Int32, y : Int32, z : Int32)
    # this calls `new (UseGC) Point3D {x, y, z}`
  end
end

pt = Point3D.new x: 1, y: 2, z: 4

Some aggregate types in Qt are QPainterPath::Element and the QStyleOption hierarchy. Wrapping these types as Crystal classes rather than lib structs means their methods no longer have to be reimplemented on the Crystal side (this is generally true for "structs" in many C++ APIs).

The rules for aggregate initialization have changed in every C++ version. This PR follows the C++11 rules. The rules can be relaxed if Bindgen uses a more recent C++ standard requirement:

Papierkorb commented 3 years ago

Sorry for the delay! Will look into this today or tomorrow at last. I think the feature itself is awesome šŸ‘

Papierkorb commented 3 years ago

Does this work with copied structs?

HertzDevil commented 3 years ago

lib structs come with this capability already, as do record structs. The major difference is that lib structs permit zero initialization if some of the fields are omitted, because their constructors are implemented as macros:

lib Binding
  struct Point
    x : Int32
    y : Int32
  end
end
# the following expands to:
# __temp_123 = Binding::Point.new
# __temp_123.x = 1
# __temp_123
Binding::Point.new(x: 1).y # => 0

# the following expands to:
# struct RecPoint
#   def initialize(@x, @y = 5) end
# end
record RecPoint, x : Int32, y : Int32 = 5

# this PR would generate: (provided C++14 rules are used)
struct MyPoint
  def initialize(*, x : Int32, y : Int32 = 5) end
end

The second difference is both lib structs and this PR require named arguments, whereas record allows positional ones.

Papierkorb commented 3 years ago

Thank you šŸ‘