On Tue, 2016-03-22 at 18:27 +0000, Andrea Giammarchi wrote:
> Thanks Giovanni, that would solve only if `GLocalFile` will still
> implements everything monkey-patched on `Gio.File` otherwise the lie
> is gonna be a disaster in terms of expectations:
> 
> ```js
> Gio.File.prototype.allFiles = function () { /* do something */ };
> Gio.File.new_for_path('/').allFiles(); // throws an error if it
> doesn't inherit
> ```

Right, that's exactly what you cannot do: they are separate objects,
changing one does not affect the other.

> To restate my concern: I would like to have instances implementing
> interfaces be runtime aware of changes to such interfaces, otherwise
> there's no way to patch upfront in a consistent way any prototype
> which is not future proof or polyfill friendly, because you cannot
> patch instances unless you wrap all of them, which is the Proxy mess
> I've recently dropped due performance implications (faster on
> bootstrap, catastrophic while running)

That will require changes in gjs I am afraid.
The code involved is in gi/object.cpp at object_instance_new_resolve()
for object prototypes, and gi/interface.cpp at interface_new_resolve()
for "interface" prototypes.

The functions are called to "resolve" a property, that is, to make it
lazily appear when the code is referencing it.
One way to do so is to modify object_instance_new_resolve(), check if a
property with that name exists on the interface object, then resolve to
an accessor property that forwards to the interface.
A little hackish, and probably with a lot of overhead to define the
accessor property in C++, but it should work.

> Is anyhow clearer what I am expecting? Yeah, I understand it won't
> work now ... but at least I hope it's clear.
> 
> Best Regards

Cheers,

Giovanni

> 
> 
> 
> 
> 
> On Tue, Mar 22, 2016 at 6:05 PM, Giovanni Campagna <scampa.giovanni@g
> mail.com> wrote:
> > Ok, let's try a factual response...
> > 
> > On Tue, 2016-03-22 at 17:24 +0000, Andrea Giammarchi wrote:
> > > > There is not even any Gio.LocalFile known to JS.
> > >
> > > ```js
> > > const a = imports.gi.Gio.File.new_for_path('./a.js');
> > >
> > > // here the "now known to JS" Gio.LocalFile.prototype
> > > Object.getPrototypeOf(a).shenanigans = true;
> > >
> > > const b = imports.gi.Gio.File.new_for_path('./b.js');
> > >
> > > // all instances affected indeed
> > > print(b.shenanigans); // true
> > > ```
> > >
> > > > It's not exposed in the GIR file, so there is never a prototype
> > > object created in the first place
> > 
> > Yes, there is a prototype object created. Every JS object with
> > custom
> > behavior has a custom prototype object in SpiderMonkey, that's just
> > how
> > it is.
> > 
> > This prototype object is "GLocalFile", and it's stored in an
> > invisible
> > object that exists just to reference it, as well as other hidden
> > classes that appear through GType but not through introspection.
> > 
> > It's supposed to be mostly invisible, but it's unavoidable.
> > 
> > > There is:
> > >
> > > ```js
> > > const a = imports.gi.Gio.File.new_for_path('./a.js');
> > > // here the *shared* Gio.LocalFile.prototype
> > > Object.getPrototypeOf(a);
> > > ```
> > >
> > > > In GJS, you can check if an object implements an interface with
> > > myObj.constructor.implements(Gio.File).
> > >
> > > That's good to know, thanks, yet if you read first messages of
> > this
> > > thread it was about patching upfront and not at runtime.
> > > I understand I can find at runtime pretty much anything I want,
> > but
> > > since there is an introspection ability, why are there
> > undocumented
> > > instances around with undocumented prototypes?
> > >
> > > Or better, why `Gio.File.new` creates something unrelated with
> > > `Gio.File.prototype` or `Gio.File` methods ?
> > > Since this super secret thing is easily leaked, why not fixing
> > this
> > > instead of saying that it shouldn't be known?
> > 
> > You can't fix that.
> > 
> > The truth is, Gio.File is a lie.
> > Indeed, Gio.File.prototype.replace_contents !==
> > (Gio.File.new_for_path('/foo')).replace_contents
> > 
> > What it means is that Gio.File is an object that exists only to
> > hold
> > methods that quack like the actual interface methods, if you call
> > them
> > explicitly with say
> > Gio.File.prototype.replace_contents.call(file, "bla")
> > , but has nothing to do with the interface methods exposed on each
> > object.
> > 
> > The reason for this is that prototype inheritance is single, but a
> > GObject class can have multiple interfaces, so there is no good
> > place
> > to put Gio.File.prototype on the prototype chain from file to
> > Object.prototype (in a way that's generic and consistent with say,
> > Gtk.Label and Gtk.Buildable).
> > So what happens is that every class that also implements an
> > interface
> > will resolve all interface methods on its own prototype.
> > 
> > In the Gtk.Label case, Gtk.Label implements Gtk.Buildable and
> > Gtk.Widget implements Gtk.Buildable, both visible in the GIR, which
> > means
> > Gtk.Label.prototype.hasOwnProperty('custom_tag_start') === true
> > and
> > Gtk.Widget.prototype.hasOwnProperty('custom_tag_start') === true
> > 
> > In the GLocalFile case, GLocalFile implements Gio.File, and we know
> > that from GType at runtime, so
> > window.<invisible
> > name>.GLocalFile.prototype.hasOwnProperty('replace_contents') ===
> > true
> > but you don't know that unless you poke at Object.getPrototypeOf
> > 
> > Yes, this is very awkward if you monkey patch prototypes, but
> > that's
> > just how it is.
> > 
> > > The reason I've asked is that I've discovered there are hidden
> > > classes the GIR won't tell me, doesn't know, but **are** on my
> > way.
> > >
> > > > I don't believe Spidermonkey would support overloading
> > instanceof
> > > for this
> > >
> > > `instanceof` is the most easily "overloaded" ( not actually
> > > overloaded, it just checks
> > > `rightSide.prototype.isPrototypeOf(leftSide)` ) operator which is
> > why
> > > I am asking if this would ever be solved.
> > 
> > Now, if we tell a lie, we should at least be consistent about it,
> > and
> > that's why
> > Gio.File.new_for_path('/') instanceof Gio.File
> > should return true
> > 
> > Checking the prototype would not work, but instanceof can be
> > overloaded
> > "properly", because after all we have access to the C API of SM and
> > we
> > can do what we want.
> > 
> > Indeed, that's https://bugzilla.gnome.org/show_bug.cgi?id=587030
> > which has had patches for a while and probably needs a rebase, but
> > would make the Gio.File lie less visible to programmers.
> > 
> > Hope this clarifies the situation, and cheers,
> > 
> > Giovanni

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
javascript-list mailing list
javascript-list@gnome.org
https://mail.gnome.org/mailman/listinfo/javascript-list

Reply via email to