This is good information in general; please post it to the Gnome Vala wiki
if it is not already there!

On Wed, Oct 13, 2010 at 9:03 PM, Evan Nemerson <[email protected]> wrote:

> There are a couple different things going on here, but it is pretty
> simple if you take the time to understand what is going on instead of
> just copying and pasting from examples.
>
> As you are probably aware, Vala translates everything to C, and then the
> C is then compiled to object code. One of the things that makes Vala a
> good choice for programming in is that software written in Vala provides
> a very usable C API, making it possible to use without too much effort
> from virtually every other language. In contrast, code written in almost
> any other language is extremely difficult to call from C, or almost any
> other languages. The big exception to this is that languages written for
> a virtual machine can often interact easily with other languages written
> for that same virtual machine (e.g., Scala can call Java code, C# can
> call VB.NET code, etc.).
>
> I think everyone would agree that this is an extremely valuable asset
> for Vala to possess, but there are a few interesting consequences. All
> of your difficulties, it seems, relate to how Vala translates things to
> C and what the tools you've chosen to use expect.
>
> Unlike .NET or Java, which are compiled to an intermediate language [1],
> or interpreted languages such as JavaScript or Python, valac must
> translate symbols into a single flat namespace (basically, a big list of
> symbols with no concept of namespaces, classes, structs, interfaces,
> etc.). Furthermore, Vala must compile to something that is usable from
> C, which eliminates using the possibility of using special characters
> like C++ does (Vala can't convert Namespace.Class.method to
> @Namespace/Class#method, because that isn't a valid C identifier).
> Instead, when Vala needs to write a method name it first takes each
> parent symbol and converts it from camel case to underscores and
> lowercases the result (FooBarBaz becomes foo_bar_baz), then concatenates
> the resulting strings into one long identifier (FooBar.Baz.run would
> become foo_bar_baz_run).
>
> For type names, Vala will keep the camel case and simply concatenate it
> all together (Foo.Bar.Baz would become FooBarBaz). There are some
> special cases revolving around constructors and asynchronous functions,
> but that's not really important right now. What is important is that not
> only does this generate an API that works well from C, but it generates
> an API that conforms to what most people would expect a C API to look
> like, especially if they are used to GObject-based code.
>
> Obviously, trying to get programmers to adhere to a single coding style
> is a bit like herding cats, so there are going to be exceptions to this.
> Vala is able to accommodate these use cases by use of CCode attributes
> [2]. Most commonly (and simplifying a bit):
>
>      * cprefix is primarily used for namespaces. While when left to its
>        own devices valac will simply concatenate the parent names to
>        generate C type names, setting the cprefix allows you to
>        override this. For instance, assuming you have a class
>        Foo.Bar.Baz, setting a cprefix of "Fubar" on a your Bar
>        namespace will result in a C name of "FubarBaz" for the Baz
>        class.
>      * lower_case_cprefix will override everything up to the start of
>        the method name. For instance, a method named Foo.Bar.baz would
>        normally result in a C name of foo_bar_baz. However, if you set
>        the lower_case_cprefix of the bar class to be "fb_" [3], the
>        resulting C name would be "fb_baz".
>      * cname will set the C name to exactly what you specify here. For
>        instance, if you set the cname of a Foo.Bar.baz method to
>        "bacon", the name of the Foo.Bar.baz function in C will be
>        "bacon".
>
> GTK+ builder was designed to work with C applications. So, when you tell
> it that the callback name for it to autoconnect to should be "baz", it
> is going to look for a symbol named "baz". If you have a Foo.Bar.baz
> method in Vala, GTK+ builder is not going to find it (if it did, what
> happens when you have both a Foo.Bar.baz and a Bar.Foo.baz?). In other
> words, GTK+ builder is looking for the C symbol you specify, so you need
> to either figure out how Vala is going to translate your symbol name, or
> tell it how to translate your symbol name (with CCode attributes).
>
> Once you've made sure GTK+ builder is getting the correct symbol name,
> you need to worry about how that function is called. In most C APIs, the
> instance data is the first argument, and Vala adheres to this
> convention. If you have a Foo.Bar.baz (int x) method (where bar is a
> class), you'll see a C function that looks something like this:
>
> void foo_bar_baz (FooBar* self, int x);
>
> The problem is, most callbacks do things a bit different--they put the
> instance data last (really they don't have an instance data parameter,
> they have a void* user_data which could be anything, but Vala uses for
> instance or closure data. That's not really important right now,
> though).
>
> When you are connecting a callback in Vala, valac will usually
> automatically create a wrapper function which translates from from the
> callback style (instance data last) to the standard style (instance data
> first). The only time this doesn't happen is when you cast a delegate,
> so if you're going to cast a delegate be sure you know what you're
> doing!
>
> Since you are using GTK+ builder to connect your signals, Vala has no
> way of knowing that it should create this wrapper, and even if it did it
> would have a different name than your method (two symbols can't have the
> same name). So, what you have to do is tell it that, when it generates
> the C, the instance data should be the last parameter, not the first.
> You do this by setting the instance_pos CCode attribute to -1... Of
> course it can be things other than -1--there are loads of examples of
> this in the vapis, but be sure you understand the implications of
> changing it.
>
> Finally we come to the i18n/l10n support. In order to make the API as
> easy to use as possible (specifically, on a C level), gettext forces you
> to define a GETTEXT_PACKAGE variable so that it can use that package by
> default. For instance, if you set define GETTEXT_PACKAGE as "foo", you
> can just do _("string to translate") instead of dgettext ("foo", "string
> to translate"). There are several ways to do this, and what I would
> suggest would depend on your build system (basically, pass
> -DGETTEXT_PACKAGE="foo" to gcc somehow).
>
> By now, it is probably obvious why the config.vapi you pasted was
> causing problems. You set the lower_case_cprefix to "" for the Foo
> namespace, which means that instead of the C symbol for Foo.bar
> generating the C symbol "foo_bar", it will just generate "bar". Your
> solution was to add a cname annotation to get the c name for your method
> back to what it should be, but what you probably really want is to just
> set the cname for Foo.GETTEXT_PACKAGE to "GETTEXT_PACKAGE", and leave
> the Foo namespace alone.
>
>
>
> [1] http://en.wikipedia.org/wiki/Intermediate_language
> [2] http://live.gnome.org/Vala/Manual/Attributes#C_code_attributes
>
>
>
> On Wed, 2010-10-13 at 21:14 +0200, Tomasz Jankowski wrote:
> > Hello!
> >
> > II'm working on GTK+ based application and I decided to use Vala to make
> my
> > life easier. I was wrong (partly)...
> >
> > I design windows in Glade and then load created XML files GTK+ Builder.
> > According to samples at Vala's homepage I added additional attributes to
> my
> > code to used callbacks autoconnect:
> >
> > [CCode (instance_pos = -1)]
> >
> > public void on_about_menu_item_activate (Gtk.MenuItem menu_item)
> > {
> >     AboutDialog dialog = new AboutDialog ();
> >
> >     dialog.display ();
> > }
> >
> > Later I decided to add internationalization support and because I use
> > Autotools I looked how it's done in http://github.com/tadeboro/Sampala .
> My
> > config.vapi:
> >
> > [CCode (prefix = "", lower_case_cprefix = "", cheader_filename =
> > "config.h")]
> >
> >
> > namespace Foo
> > {
> >
> > /* Package information */
> >
> > public const string PACKAGE_NAME;
> >
> > public const string PACKAGE_STRING;
> >
> > public const string PACKAGE_VERSION;
> >
> >
> >  /* Gettext package */
> >
> > public const string GETTEXT_PACKAGE;
> >
> >  /* Configured paths - these variables are not present in config.h, they
> are
> >
> > * passed to underlying C code as cmd line macros. */
> >
> > public const string LOCALEDIR;  /* /usr/local/share/locale  */
> >
> > public const string PKGDATADIR; /* /usr/local/share/sampala */
> >
> > }
> >
> > I also added flags: "--vapidir=. --pkg=config" to Vala compiler
> (config.vapi
> > is placed in the same directory that source code files are) and flags to
> > GCC: -include
> > $(top_srcdir)/config.h -DLOCALEDIR=\""$(localedir)"\"
> > -DPKGDATADIR=\""$(datadir)"\"
> >
> > When I added config.vapi to my project it broke callbacks autoconnect
> (but
> > localization works fine), runtime errors:
> >
> > (foo-gtk:24482): Gtk-WARNING **: Could not find signal handler
> > 'foo_on_quit_menu_item_activate'
> >
> > (foo-gtk:24482): Gtk-WARNING **: Could not find signal
> > handler foo_on_about_menu_item_activate'
> >
> > etc.
> >
> >
> > I stared reading Vala documentation, searching web and finally I figured
> > out, that this construction works fine for me:
> >
> > [CCode (instance_pos = -1, cname = "foo_on_about_menu_item_activate")]
> > public void on_about_menu_item_activate (Gtk.MenuItem menu_item)
> > {
> >     AboutDialog dialog = new AboutDialog ();
> >
> >     dialog.display ();
> > }
> >
> >
> > Questions:
> >
> >    1. Why config.vapi addition broke callbacks autoconnecting?
> >    2. Is there any other way to achieve the same result
> >    without writing cname attribute for each callback?
> >    3. What does instance_pos attribute?
> > _______________________________________________
> > vala-list mailing list
> > [email protected]
> > http://mail.gnome.org/mailman/listinfo/vala-list
>
>
> _______________________________________________
> vala-list mailing list
> [email protected]
> http://mail.gnome.org/mailman/listinfo/vala-list
>
_______________________________________________
vala-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/vala-list

Reply via email to