Search code examples
signals-slotsreturn-typevala

How do return types for signals work in Vala?


In Vala I can write a class like this:

class Foo {
    public signal int foo();
}

where the return type of a signal is non-void. How does this work? What will the result of the signal emission be if there is no listener or more than one listener connected to the signal? I can't seem to find any documentation on this.


Solution

  • Vala will just inherit how GObject handles such a situation:

    Note that g_signal_emit() [and most other emitting methods] resets the return value to the default if no handlers are connected, in contrast to g_signal_emitv() [which passes by an output GValue and just leaves it alone in that case]

    You can see the Vala version of that doc here. Emitting the signal with some_foo.foo() will just delegate to that ultimately, as testing will show:

    class Foo
    {
      public signal int foo();
    }
    
    public static int
    main(string[] args)
    {
      Foo foo = new Foo();
      // foo.foo.connect( () => { return 42; } );
      int result = foo.foo();
      return result;
    }
    

    With the line that calls .connect() commented out, the result is 0, which is the default value for a GValue holding an int.

    That's for the case of zero handlers. For multiple, as stunningpotato indicated, the return value will, typically, be the result of the last signal handler that gets called:

    If no accumulator function was provided, the value returned by the last handler run will be returned by g_signal_emit.

    And, excepting object-provided handlers, you can control which the last is:

    The user-provided signal handlers are called in the order they were connected in.

    As the 1st of those docs says, you can pass a custom accumulator to decide what happens with the results of multiple handlers, to handle more complex cascades.