Re: Bikeshedding the gnome-class mini-language
- From: Federico Mena Quintero <federico gnome org>
- To: Sebastian Dröge <slomo coaxion net>, rust-list <rust-list gnome org>
- Subject: Re: Bikeshedding the gnome-class mini-language
- Date: Tue, 24 Oct 2017 19:03:29 -0500
On Wed, 2017-10-25 at 00:27 +0200, Sebastian Dröge wrote:
Do you plan to also add support for public fields in the instance
struct?
Nope. This has made it all to easy to break the ABI in the past, and
all of GTK+ has moved to private structs, anyway.
I realize that public fields may be convenient for "internal" GObjects
that are never exported, though. Maybe we have different use cases in
mind? (I'm all about libraries with GObject Introspection.)
Speaking of ABI... the signals and virtual methods of a class *are*
part of the FooClass struct's ABI. While C uses things like
pub struct GtkBoxClass {
pub parent_class: GtkContainerClass,
pub _gtk_reserved1: Option<unsafe extern "C" fn()>,
pub _gtk_reserved2: Option<unsafe extern "C" fn()>,
pub _gtk_reserved3: Option<unsafe extern "C" fn()>,
pub _gtk_reserved4: Option<unsafe extern "C" fn()>,
}
maybe we should have something like
gobject_gen! {
class Foo {
...
reserve_slots(N); // to be decremented when needed
}
}
private_init() is a mandatory function that gets called during
This should probably take the instance as parameter, or a different
function for hooking into instance_init would be useful. To set-up
any
things that might be necessary for the base-class to properly
initialize everything.
The idea is that private_init() returns a FooPrivate struct, without
ever having the chance to look at uninitialized memory.
To set up extra things, we can very well have an init(&self) {} block
or something. I suppose this ties with the discussion on constructors
below.
Then it should also be possible to impl derive for the struct
manually,
the default derived impl is not always possible/correct :)
Something like
gnome_class! {
class Foo {
struct FooPrivate {
...
}
impl Default for FooPrivate {
...
}
}
}
?
You know, that may be more Rust-like than the whole private_init()
thing. Do you like it better?
I'm torn between putting the "impl Blah for Bleh" inside or outside the
class block. If I were trying to make this look more like an extension
to the language, maybe something like
gnome_class! {
class Foo: Superclass {
private = FooPrivate; // similar to associated types, "type Foo = Bar;"
// should we put the init/constructor/etc here?
fn init(&self) {
...
}
fn constructor(&self) {
// how do we pass in the construct properties comfortably?
}
}
struct FooPrivate {
...
}
// or #[derive(Default)] above if it works for you
impl Default for FooPrivate {
fn default() -> FooPrivate {
...
}
}
// this defines the class ABI, basically
impl Foo {
pub fn static_method(&self, ...) {
...
}
virtual fn virtual_method(&self, ...) {
...
}
fn this_private_method_is_an_implementation_detail(&self) {
// and is not exported or put in the class slots
}
signal some_signal(&self, ...);
signal with_default_handler(&self, ...) -> Bar {
// default handler code goes here
}
}
// or just "impl Superclass for Foo"?
// I kind of like making it obvious that these are overriden things
override Superclass for Foo {
fn overriden_method(&self, ...) {
...
}
signal overriden_signal_handler(&self, ...) {
...
}
}
override AnotherSuperclass for Foo {
// same as above
}
impl SomeInterface for Foo {
fn blah(&self, ...) {
}
}
}
Note the init()/constructor() inside the "class" block.
I haven't gotten to the set_prop/get_prop stuff yet. If you figure out
a nice syntax for them, feel free to add it here :)
Also, what about dispose/finalize? In the old code generator,
::finalize() would just Drop the private struct; we don't provide a
good place to put a custom Drop implementation, but with the scheme
above, it is easy to put an "impl Drop for FooPrivate" along with "impl
Default for FooPrivate".
Should we have a fake "impl Dispose for Foo" that must have a "fn
dispose(&self)", or add a fake function dispose() along with the
init()/constructor() above?
Could also use a construct {} block for that, it seems like a
reasonable choice. Similarly for class and base construct blocks.
Hmmm, how would you notate those in the scheme above? Or some other
scheme?
public MyConstructor (int a, int b, int c) {
Object (some_construct_only_prop: a, some_other_prop: b);
// construct superclass
this.my_own_prop = c;
}
I assume this would only take CONSTRUCT properties, and not all of
them, and there can only ever be a single constructor like this?
I don't know if Vala lets you have multiple constructors; it doesn't
sound terribly hard to support them. Right now I'm a bit more
uncertain on how to get the construct-time properties to a constructor
function :)
virtual implies public IMHO
I agree!
[signal accumulators]
We use them quite often in GStreamer. You basically need them
whenever
you have a non-trivial return value, or you want to use your return
value to decide if further signal handlers have to be called.
I can give examples if needed.
This would be very helpful - in your gobject-example-rs?
You could provide them by name in the signal attribute.
signal my_signal(&self, ...)
where accumulator(i_dont_even_know_the_params)
Syntax ideas appreciated :)
What about the class/default handler, how would you handle that?
Just by writing
signal my_signal_with_default_handler(&self, x: i32) {
println! ("default handler {}": x);
}
That would generate a function and assign its function pointer to the
signal's slot in the class.
Sorry to put so much pressure on the syntax right now - it's just that
writing syn parsers that mix a made-up language with syn's own view of
Rust constructs... is not the most pleasant thing, but I'm getting
better at it :)
Federico
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]