On 13 June 2017 at 05:48, <philip.chime...@gmail.com> wrote:

> On Mon, Jun 12, 2017 at 2:36 PM Sam Jansen <sam.jan...@starleaf.com>
> wrote:
>
>> On 11 June 2017 at 00:04, <philip.chime...@gmail.com> wrote:
>>
>>> On Fri, Jun 9, 2017 at 2:29 PM Sam Jansen <sam.jan...@starleaf.com>
>>> wrote:
>>>
>>>> Hello,
>>>>
>>>> I've been following in the steps of some others [1] [2] who have
>>>> attempted to produce Typescript definitions for Gtk and Gjs. I believe I
>>>> have something more complete than any other effort I've found, so I thought
>>>> it was time to share my work, and a couple of questions.
>>>>
>>>> Starting with gir2dts [2], I tried to write a basic application... And
>>>> failed. Due to various limitations (no constructors, interfaces, etc.) So I
>>>> went about at fixing any limitation I found and have ended up with a fairly
>>>> thorough description in Typescript of the GI interfaces presented by Gjs.
>>>>
>>>> Examples of some features I'm particularly happy with:
>>>>
>>>>    - Signals, via the connect() function, are checked using
>>>>    Typescript's string literal type checking [3]
>>>>    - The above includes the "notify::attribute" syntax
>>>>    - All possible parameters for a class are described in an
>>>>    interface, and this is used in the default Gjs constructor. This allows
>>>>    editors like Visual Studio Code to provide code completion and type
>>>>    checking for the arguments to this object
>>>>    - Classes are decomposed into static and instance sides. The static
>>>>    side is used to describe the Gjs constructor, and then extended with the
>>>>    other GI constructor functions
>>>>    - Ability to include the documentation, such that it will be shown
>>>>    in code completion popups
>>>>    - Multiple return values described correctly
>>>>
>>>>
>>>> All of this is possible due to the excellent work of the original
>>>> project, gir2dts, that I have simply forked and added extra support to.
>>>>
>>>> This project is available at: https://github.com/sammydre/gir2dts
>>>>
>>>
>>> This is *fantastic*.
>>>
>>>
>>
>> Thanks :)
>>
>>
>>> I'm still not sure it's all that useful generally just yet -- largely
>>>> due to me not knowing how such code should be distributed, or work with
>>>> module systems. Any comments on how to structure this would be appreciated.
>>>>
>>>
>>> I admit I don't know much about Typescript. If I understand correctly,
>>> this would be a plugin for the Typescript compiler, so it should be
>>> distributed in whatever way is usual there.
>>>
>>>
>>
>> It seems the way most people are using it now is via "@typings", which is
>> supported by npm.
>>
>> I think the best thing for me to do is document what I have at the moment
>> / write a good example and point to it here to solicit further discussion.
>> So I'll come back to this at some point in the future, all going well.
>>
>
> Yes, an example and/or "getting started" document would be quite useful!
>
>
Well, this led me down quite the rabbit-hole...

The end result is that I've completely rewritten the tool, this time in
Typescript, and with *much* fewer hacks, and I believe overall a more
correct approach. The tool is now at:

https://github.com/sammydre/ts-for-gjs

This includes sample output, e.g.:

https://github.com/sammydre/ts-for-gjs/blob/master/out/GLib.d.ts

And a couple of sample programs:

https://github.com/sammydre/ts-for-gjs/blob/master/examples/browser/main.ts
https://github.com/sammydre/ts-for-gjs/blob/master/examples/editor/main.ts

The example programs are fairly boring -- they are pretty much just JS. The
magic comes in the type-checking, autocompletion, etc. which isn't really
easy to see without using it! If anyone wants to play; check out the github
project then open the directory in visual studio code, "npm install", and
it should all "just work".

You'll also see here how I've implemented modules: just with relative path
imports in typescript. Typescript then compiles this to "require"
statements, which I bundle together with webpack right now; but this isn't
strictly required.


> [...]
>
>>
>>>>    - I've sometimes found that derived functions have different
>>>>    signatures, with Typescript does not like. An example of this is the
>>>>    "activate" symbol used in Gtk; consider "Widget.activate()" vs.
>>>>    "Button.activate(button: Button)" -- Button derives from Widget, but 
>>>> has a
>>>>    different signature for this method. What does Gjs do about this? "let 
>>>> a =
>>>>    new Gtk.Button({}); a.activate()"
>>>>
>>>> There is no Gtk.Button.activate() method. I guess you are probably
>>> referring to the virtual method, which is called vfunc_activate() in GJS.
>>> Virtual methods are not called directly from JS code, instead you would add
>>> a vfunc_activate() method to a subclass of Gtk.Button if you wanted your
>>> subclass to have different or additional behaviour from the default
>>> Gtk.Button. (And the button parameter is lopped off, since it's bound to
>>> "this" inside the method.) This method would only be called internally by
>>> GTK.
>>>
>>> If you execute new Gtk.Button().activate() it calls
>>> gtk_widget_activate().
>>>
>>> The documentation in our DevDocs instance might shed some light here
>>> [8]; as far as I know it generates all the method signatures correctly, and
>>> you can feel free to borrow from that code.
>>>
>>
>> I chose a bad example here. It showed that I had completely misunderstood
>> the GI "virtual functions" and their mapping to GJS. Based on your input,
>> I've now fixed that.
>>
>> But my question still stands, albeit with slightly different classes.
>> Consider:
>>
>>    - Gtk.MenuItem.activate() : http://devdocs.baznga.org/
>>    gtk30~3.22.12/gtk.menuitem#method-activate
>>    <http://devdocs.baznga.org/gtk30~3.22.12/gtk.menuitem#method-activate>
>>    - Gtk.Widget.activate() : http://devdocs.baznga.org/
>>    gtk30~3.22.12/gtk.widget#method-activate
>>    <http://devdocs.baznga.org/gtk30~3.22.12/gtk.widget#method-activate>
>>
>>
>> MenuItem derives from Widget (via Bin via Container).
>>
>> The activate() method has a different signature. For widget, it returns a
>> boolean. For MenuItem, it returns void.
>>
>> What does GJS do in this case? Will calling activate() always result in
>> calling the MenuItem version on a MenuItem instance, making it impossible
>> to call the Widget version directly? Or something else?
>>
>
> Oh, I see now what you mean. I didn't even know this gotcha existed! Like
> properties and methods with the same name, I would consider that a bug in
> GTK.
>
> I'm not sure off the top of my head which one will take priority. I
> suspect the one from the "most derived" class (Gtk.MenuItem) would hide the
> Gtk.Widget method.
>
> However, you can call either one explicitly by executing
> Gtk.Widget.prototype.activate.call(widget) or Gtk.MenuItem.prototype.
> activate.call(widget).
>

That makes sense, it's very helpful.

I eventually came to the conclusion that there is fundamentally a mismatch
here between the "inheritance" one can describe in Typescript, and that
used today in the GI bindings to especially GTK. There are a number of
cases where the derived method/property doesn't match exactly. Rather than
try and enumerate these all by hand and hack around them, I decided it's
best not to use Typescript's inheritance, and just describe the complete
set of methods and properties, resolving them all from the inheritance tree
I look up in the GI info. Hence you'll see the Gtk.d.ts file is rather
large (i.e. 6MB!)

Finally, a problem I created for myself with types was wanting a vaguely
safe way to down/up-cast. So I invented the rather hacky "giCast" function
as defined here:

https://github.com/sammydre/ts-for-gjs/blob/master/out/cast.ts#L691

I have a question: is there a better way to figure out what actual class an
instance is at run-time? You can see here what I do is call toString() on
it, then parse out the resulting string that has a "GIName:" in it. This
works, but feels rather brittle...

As things stand, this works well for me, and I'll continue to fix up bugs
and limitations in the declarations as I find them (or they're reported to
me).

Cheers,
Sam


>
>
>> BTW, the devdocs is very useful - I didn't know that existed before your
>> email!
>>
>
> The docs have not spread so wide yet; we had them up for a while, then
> they were gone for a while, and now they're back up, hopefully for good.
>
> [1]: https://github.com/niagr/GIR2TS / https://github.com/niagr/gjs-ts
>>>> [2]: https://www.npmjs.com/package/gir2dts
>>>> [3]: https://www.typescriptlang.org/docs/handbook/advanced-types.html
>>>> [4]: https://people.gnome.org/~gcampagna/docs/Gtk-3.0/Gtk.
>>>> Window.is_active.html
>>>> [5]: https://people.gnome.org/~gcampagna/docs/Gtk-3.0/Gtk.
>>>> Window-is-active.html
>>>>
>>>
>>> [6] https://bugzilla.gnome.org/show_bug.cgi?id=690450#c30
>>> [7] https://bugzilla.gnome.org/show_bug.cgi?id=688650
>>> [8] http://devdocs.baznga.org/gtk30~3.22.12/gtk.button#vfunc-activate
>>>
>>
_______________________________________________
javascript-list mailing list
javascript-list@gnome.org
https://mail.gnome.org/mailman/listinfo/javascript-list

Reply via email to