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
