Cannot implement vfunc `Gtk::Widget#do_measure`
BlobCodes opened this issue · 5 comments
Trying to implement the vfunc measure
results in a compile-time error:
Showing last frame. Use --error-trace for full trace.
There was a problem expanding macro '_register_do_measure'
Code in macro 'method_added'
3 | _register_do_measure
^
Called macro defined in lib/libadwaita/lib/gi-crystal/src/auto/gtk-4.0/widget.cr:5053:13
5053 | private macro _register_do_measure
Which expanded to:
> 20 | raise GICrystal::ObjectCollectedError.new if __temp_46 || __temp_47.null?
> 21 |
> 22 | __temp_47.as(self).do_measure(orientation, for_size, minimum, natural, minimum_baseline, natural_baseline)
^------
Error: undefined local variable or method 'minimum' for Mangaba::UI::Description.class
I think this is because the last four arguments are of type Int32*
as four Int32 should be returned using pointers.
out
params aren't handled by ArgStrategy in Direction::CToCrystal
mode yet, the code used by vfunc is the same made for signals, and there's no signals with out parameters.
We need to think how to "crystallize" this API, maybe letting measure
return a tuple with these out
parameters 🤔
The signature would be:
do_measure(orientation : Gtk::Orientation, for_size : Int32) : {Int32, Int32, Int32, Int32}
I would not like to expose pointers in the API
Or... we could let the signature return a NamedTuple:
do_measure(orientation : Gtk::Orientation, for_size : Int32) : {minimum: Int32, natural: Int32, minimum_baseline: Int32, natural_baseline: Int32}
The signature is longer and uglier, but less error prone to use in these cases of many out parameters.
There's also the alternative of mix between two... if there's just 2 out parameters, the return type is a tuple, starting from 3 parameters, a named tuple.
I tempted to choose that named tuple approach, despite of long to type it's safer... and BTW the user doesn't need to type the return type restriction in the method declaration.
We need to think how to "crystallize" this API, maybe letting measure return a tuple with these out parameters
Often, it is allowed to set the pointers of the out parameters to NULL. In this case, the caller does not want a value. This is not really possible to communicate with Tuples. Maybe we can create an Out(T)
type with only two methods #writable?
and #value=
that is just a pointer in disguise.
The Out(T)
approach is a bit Cish, however it's needed if the out parameter, if used, implies in some extra processing by the function.
Maybe we could do both approaches:
- Bind it using a method with
Out(T)
, for these uses cases where not setting some parameter matters.- The out parameters needed to be named arguments.
- Bind it using a method that returns tuples/named tuples.
- The internal implementation could be using the
Out(T)
version to make things simpler.
- The internal implementation could be using the
As their signature are different, they can have the same name, nowadays something similar is done when the method receives an array, there's a method that receives the array and another one that receives a variable number of arguments doing a splat.
I'm going to work on this soon, since it become a blocker for my app due to some Pango functions that return multiple items.
I'm going to work on this soon, since it become a blocker for my app due to some Pango functions that return multiple items.
I need to never do any promises about what I'm going to fix/implement, since it depends on a combination of free time, mood and necessity, all 3 are not always present.
This is not really possible to communicate with Tuples.
It is, however you will need to write some nils, however I think for simplicity this will end up being implemented (some day) only as named tuples return values:
class FooWidget < Gtk::Widget
@[GObject::Virtual]
def measure(orientation, size)
{minimum: 10,
natural: 100,
minimum_baseline: 10,
natural_baseline: 10}
end
end
I was implementing the measure
virtual func in a project of mine, doing it manually to check how a proposed API for it would look like... and this NamedTuple idea looked not good at all. I'll follow with the GICrystal::Out
type when implementing this in the future.
struct Out(T)
@pointer : Pointer(T)
delegate value=, to: @pointer
end
This Out
type will be basically a wrapper to stdlib Pointer, what made me think if just throwing pointers in the vfunc API without this makeover would be enough, or at least simpler to implement in the generator.