Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to find out keyword arguments to (make <Type> ...)? #118

Open
ZelphirKaltstahl opened this issue Jan 26, 2022 · 7 comments
Open

How to find out keyword arguments to (make <Type> ...)? #118

ZelphirKaltstahl opened this issue Jan 26, 2022 · 7 comments

Comments

@ZelphirKaltstahl
Copy link

I would like to know a way to find out the names of keyword arguments of a call like:

(make <GtkApplication> ...)

Not for that one specifically, but a general method to find out about the arguments. For example I tried to create a GMenuItem instance:

(gi:make <GMenuItem>
               ;; #:text "test"
               ;; #:title "test"
               ;; #:label "Exit"
               #|#:label "Exit" #:translatable "yes" #:action "app.exit"|#)

But none of those works. I always get the error about ERROR: In procedure %make-gobject: In procedure %make-gobject: unknown object parameter. Even though https://docs.gtk.org/gio/ctor.MenuItem.new.html would seem to indicate, that the keyword argument should be #:label.

What is a good general method for finding out what I need to and what I can specify as keyword arguments?

@LordYuuma
Copy link
Collaborator

You're mixing up constructors. make is defined in terms of g_object_new, which in turn allows specifying any property that has the construct flag set. See e.g. https://docs.gtk.org/gio/property.Application.application-id.html for a property you can specify that way.

For the record, it's been a while since I last used the gi-gtkdoc script that comes with Guile-GI and can be invoked via guild, but if there's a way we could snarf this information from the official docs, this tool (or a similarly named one to adjust for changes in GNOME documentation practises) should be the one to handle it.

@spk121
Copy link
Owner

spk121 commented Mar 7, 2022

I think this question was answered, but, just in case someone else runs across it in future and wants more info...

The docs https://docs.gtk.org/gio/class.MenuItem.html show that MenuItem has no properties. If MenuItem had properties, they'd be in a properties section in the docs. That is why using the make constructor with keywords isn't doing what you want, since that kind of constructor sets properties.

The doc that you referenced at https://docs.gtk.org/gio/ctor.MenuItem.new.html is for a constructor function. guile-gi's translation will create the function (menu-item:new label detailed-action) that you can call. Note that label and detailed-action are optional string parameters.

Note that the C docs say that the label or detailed-action arguments can be NULL, that means in Scheme, these arguments can be #f or can be left off.

For an example of an object that has properties, check out https://docs.gtk.org/gtk4/class.Button.html . Button has properties like child and has-frame. Its parent class Widget has many properties: can-focus, can-target, etc.

@spk121
Copy link
Owner

spk121 commented Mar 7, 2022

Also, for the sake of comedy I guess, here's a script that'd do what you were asking specifically. This script prints out all of the properties for GtkButton.

(use-modules (gi) (gi types))
(use-typelibs ("Gtk" "4.0")
              ("GIRepository" "2.0"))

(write
 (let* ((type (get-gtype <GtkButton>))
        (baseinfo (repository:find-by-gtype (repository:get-default) type)))
   (let loop ((baseinfo baseinfo)
              (out '()))
     (if baseinfo
         (let* ((n (object-info-get-n-properties baseinfo))
                (props (map (lambda (i)
                              (get-name (object-info-get-property baseinfo i)))
                            (iota n))))
           (loop (object-info-get-parent baseinfo)
                 (append out props)))
         ;; else
         (sort out string<?)))))

@ZelphirKaltstahl
Copy link
Author

Hi! Sorry I am slow to reply and only saw the replies yesterday. I have some questions now:

@LordYuuma

You're mixing up constructors. make is defined in terms of g_object_new, which in turn allows specifying any property that has the construct flag set. See e.g. https://docs.gtk.org/gio/property.Application.application-id.html for a property you can specify that way.

So this means, that if there is construct in the brackets like on the example documentation page in property application-id: utf8 [ read, write, construct ] then I can specify it as a keyword argument in a (make ...) call? Do I understand this correctly?

(I have not really any idea about how Gio works internally and what those flags are, except for the general idea of a flag being some kind of boolean being set somewhere. No deeper Gio knowledge here.)

@spk121

The docs https://docs.gtk.org/gio/class.MenuItem.html show that MenuItem has no properties. If MenuItem had properties, they'd be in a properties section in the docs. That is why using the make constructor with keywords isn't doing what you want, since that kind of constructor sets properties.

The page https://docs.gtk.org/gio/property.Application.application-id.html does have a "Declaration" section, while the one you linked https://docs.gtk.org/gio/class.MenuItem.html does not have such a section. So generally flags would appear in a "Declaration" section, if there are any. If there is no "Declaration" section, it implies already, that there are no flags. Correct?

The doc that you referenced at https://docs.gtk.org/gio/ctor.MenuItem.new.html is for a constructor function. guile-gi's translation will create the function (menu-item:new label detailed-action) that you can call. Note that label and detailed-action are optional string parameters.

I fell victim of finding the wrong documentation page =(

I am not really sure what the difference between a "constructor" (the usual term) and a "constructor function" is in this context. Is there any? Should I be using the words "constructor function", as it is a function creating some struct, instead of an object, because it is C code underneath?

Regarding: (menu-item:new label detailed-action) -- I was under the impression, that I could always go with the (make ...) style, but perhaps that assumption is proven wrong with this example? Perhaps I should not try to use (make ...) for everything, but differ in approach, depending on what kind of widgetor other thing I need to create?

Note that the C docs say that the label or detailed-action arguments can be NULL, that means in Scheme, these arguments can be #f or can be left off.

OK thanks!

For an example of an object that has properties, check out https://docs.gtk.org/gtk4/class.Button.html . Button has properties like child and has-frame. Its parent class Widget has many properties: can-focus, can-target, etc.

There seems to be a difference between flags and properties. Flags simply being some boolean indicator of something existing and properties, which can be specified using keyword argument in guile-gi. But the keyword arguments can only be used with (make ...), if the thing I want to create has the construct flag. Otherwise there is no (make ...) call for the thing. In cases without construct flag, I have to find another way of constructing the thing. guile-gi creates some other function in that case.

Is this correct?

Also, for the sake of comedy I guess, here's a script that'd do what you were asking specifically. This script prints out all of the properties for GtkButton.

I think the idea is then, that it would be easier to browse the correct docs and extract the knowledge from there, instead of running the code to inspect properties of a thing? Nevertheless thanks for that code. Hope to be able to try soon!

Best regards,
Zelphir

@spk121
Copy link
Owner

spk121 commented Mar 8, 2022

@ZelphirKaltstahl are you a C or C++ guy? Imagine you have a struct

class Position {
public:
  double x;
  double y;
};

Using (make <Position> #:x 0 #:y 1) is like setting the public variables directly

Position p;
p.x = 0;
p.y = 1;

While a constructor function is a procedure that returns a new instance

Position* new_position(bool whatever, int whatever) { return new Position(); }

This isn't valid, but, I hope you know what I mean.

@ZelphirKaltstahl
Copy link
Author

I have used C and C++ only once or twice for assignments at university, but not really after that. My knowledge of C is very limited.

I know what a constructor is in some other languages (Java, Python, probably others). I think with the help of your example I understand:

"constructor function" is simply a function acting as a replacement for a constructor. Since there are no classes and objects in C, "constructor function" refers to a function, that does the job, which usually a "constructor" would do, if there was one. The wording "constructor function" made me think, that maybe there is a concept I do not know about, that is distinct from normal constructors. Perhaps even specific to guile-gi. Thanks for your example. If I may make a guess and to check my understanding:

Position* new_position(bool whatever1, int whatever2) { return new Position(); }

Here the arguments whatever1 and whatever2 would actually be used in the creation of a new object, as in:

Position* new_position(bool whatever1, int whatever2) { return new Position(whatever1, whatever2); }

And new_position is used as a simple function, not a language built-in concept. It is used instead of something like the following:

Position* pos = new Position(...)

Which would be using a normal "constructor", but which does not exist in C.

@LordYuuma
Copy link
Collaborator

Calling a procedure a "constructor" in an OOP language is just a way of making yourself sound smarter while omitting important details to everyoe who wants to actually learn things. All constructors, regardless of language, are if not by definition then at least by implementation procedures.

In GObject, there are two acceptable ways of constructing an object. The first is calling a procedure named SOME_TYPE_new[_WITH_VARIANT] with the correct arguments – this is what OOP gurus typically mean when they talk about constructors, but they obscure it with syntactic sugar to make it look nicer. See Vala, in which new Gtk.Window gets exactly translated to gtk_window_new. The other is g_object_new, which takes a GType and variadic arguments, which are const char*, void* pairs corresponding to key and value respectively. This might also be recognizable as a factory method if you've ever visited a class on design patterns.

In Guile-GI, make uses the g_object_new "factory pattern" constructor, not the explicit argument constructor. This makes code written with it easier to reason about than the other way round.

So this means, that if there is construct in the brackets like on the example documentation page in property application-id: utf8 [ read, write, construct ] then I can specify it as a keyword argument in a (make ...) call? Do I understand this correctly?

(I have not really any idea about how Gio works internally and what those flags are, except for the general idea of a flag being some kind of boolean being set somewhere. No deeper Gio knowledge here.)

Yes, construct means you can supply it by keyword to make. read means you can use an accessor to read the value as in (application-id app) and write that you can use a modifier to set it as in (set! (application-id app) "org.gnome.Example"). All of those are specified in GObject, not Gio.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants