Glaring GJS API issues

GNOME has a made JavaScript the preferred programming language for new applications. However, there are some glaring API issues that make Gjs confusing, and bad for normal PEOPLE who value their time. This is the list of the issues I've encountered, roughly sorted by how much I think it will deter normal PEOPLE who value their time from GNOME platform.

This is kind of my personal list, but feel free to edit and comment.

No XML

There's no XML parser besides E4X that's deprecated and going to be removed from SpiderMonkey.

Some properties registered by Gjs clash with perfectly legit property names

The most glaring example is this.parent clash with GtkWidget.parent: Bug 698283. Other ones I found are:

GObject.connect
GObject.connect_after
GObject.disconnect
GObject.emit

For example:

const MyWidget = new Lang.Class({
    Name: 'MyWidget',
    Extends: Gtk.Grid
});

let grid = new Gtk.Grid();
let widget = new MyWidget();

print(widget.parent);

Prints:

function _parent() {
    if (!this.__caller__) {
        throw new TypeError("The method 'parent' cannot be called");
    }
    var caller = this.__caller__;
    var name = caller._name;
    var parent = caller._owner.__super__;
    var previous = parent ? parent.prototype[name] : undefined;
    if (!previous) {
        throw new TypeError("The method '" + name + "' is not on the
superclass");
    }
    return previous.apply(this, arguments);
}

Easier GObject integration

Signals? Properties? GObject names? class_init?

Impossible to create a TreeIter from JavaScript

It's impossible to create custom Gtk.TreeIter from JS (no constructor), so you can't implement a completely custom Gtk.TreeModel in JavaScript.

GtkTreeIter is a simple C structure:

struct GtkTreeIter {
  gint stamp;
  gpointer user_data;
  gpointer user_data2;
  gpointer user_data3;
};

Usage:

int
foo(void)
{
  GtkTreeIter iter;
  get_iter_of_something (&iter);
  do_something_with_iter (&iter);

  /* iter is no longer needed, C frees its memory 
     automatically, but it's impossible to make it 
     call a custom function, as C doesn't have C++'s
     destructors, that's why we can't put references
     to JavaScript objects into them */
}

Although it's impossible to receive notification when a GtkTreeIter goes out of scope as C has no destructors, I think stamp is enough. JavaScript code will have to maintain an array to map from stamps to actual objects, eg.

_init: function() {
  this.parent(...);
  this._items = [];
},

getTreeIterOfItem: function(itemStamp)
{
  if (this._items[itemStamp] === undefined)
    return undefined;

  return new Gtk.TreeIter(itemStamp);
},

getItemByTreeIter: function(iter)
{
  return this._items[iter.stamp];
}

Useless string length arguments

For example, Gtk.TextBuffer.set_text(text, length). Length argument is useless, since JavaScript uses UTF-16 and length expects length of a UTF-8 string.

Binary data uses ByteArray instead of Uint8Array

For example, GFile.load_contents. Uint8Array is now officially recommended.

Useless "success" boolean

Some functions return useless "success" boolean: for example [success, contents, etag_out] = GFile.load_contents(). When C g_file_load_contents returns false, it also sets a GError, so in Gjs the function will always return true (if the C function returns false, an exception is thrown in JavaScript).

The GObject Introspection developers have already introduced "(skip)" mark for such return values, but they won't add it to existing API to avoid backwards incompatibility.

Misc thoughts

- DanWinship on the mailing lists suggested to create an imports.gnome object that behaves like import.gi, but imports fixed, new API while leaving imports.gi intact, preserving compatiability. This won't help to fix the issue with this.parent though.

NikitaChuraev/GlaringGjsApiIssues (last edited 2013-04-19 13:06:10 by NikitaChuraev)