hugopl/gi-crystal

Support to declare GObject properties

hugopl opened this issue · 3 comments

This is meant to be a discussion about the implementation of user declared GObject properties.

IMO it must be as transparent as possible, i.e. a property/setter/getter macro on GObject, overwriting the original Crystal Object macros.

class Foo < GObject::Object
  # Creates a read/write GObject property
  property foo : Int32
  # Creates a read only GObject property
  getter bar : Int32
  # Creates a write only GObject property
  setter moo : Int32 
  # Prop with blurb
  property hey : String, blurb: "I'm the property blurb"
  # Prop with cusom nick
  property nicked : String, nick: "Nickey"
end

The nick can be the name.titleize, or custom. Blurb could be default to name.titleize too

These macros would create the variables on Crystal world, so people could use @foo to read foo property without overhead.

A possible implementation for this would be the macro generate something like

@[GObject::Property(blurb: "Prop blurb"]
@foo : String

So a finalize macro would catch all instance variables with this annotation and generate the set_property/get_property methods plus the class_init that register the properties.

I didn't test this yet, but if it works we could use the same schema to vfuncs, to avoid the bug that forbid a method starting with do_ to be declared if no vfuncs with that name exists, so instead vfuncs can just be:

@[GObject::VFunc]
def do_whatever

# or

@[GObject::VFunc(name: :whatever)]
def whatever_name

But this is another subject 😁

Back to properties... other options for properties can also be added as extra parameters in the macro, e.g.:

property foo : Int32, min: 0, max: 32

Not all crystal properties can be mapped to GObject properties, therefore I would suggest using an annotation, raising an error if there is no equivalent gtype.

Also, there are modules using the getter, setter, property macros so I think we should put blurb, nick and additional arguments into the annotation.

Example:

@[GObject::Property(min: 10, max: 20, access: :read)]
@some_int : Int32

@[GObject::Property(default: -1, blurb: "this is unused")]
property something : UInt64

We still have to override the setter/getter/property macros to emit a notify signal on property change.

I'm already working on an implementation, there I just looped over the instance vars using {% for Ivar in @type.instance_vars %} and only generated a GObject property where the annotation is set.

Not all crystal properties can be mapped to GObject properties, therefore I would suggest using an annotation, raising an error if there is no equivalent gtype.

It's true, better just use the annotation so, and if the annotation is going to be explicit used, better put the property options there.

And I think we don't need to care about constructor-only properties.

Implemented on 6383125