-
Notifications
You must be signed in to change notification settings - Fork 604
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
Improve docs on functions #5446
Conversation
While learning to use slint, I noticed that a lot of behaviors (in this case about functions) aren't clearly stated in the documentation. So I'm trying to document what I've learned and hopefully make it easier for the next person.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot. This is definitively an improvement!
This introduces the notion of "target" which is kind of new in the documentation. I think "element name" might be a better term.
export component CallsFunction { | ||
property <int> test: my-friend.double(1); | ||
|
||
my-friend: HasFunction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my-friend: HasFunction { | |
my-friend := HasFunction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, fixed!
The CI is failling in the
|
Thanks! I fixed the tests (hadn't noticed them) and I reorganized things a bit to make things clearer. I also added a section on name resolution inside the function code, because I was a bit unsure about it myself -- I could see it being implemented both ways! Please take another look :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the edits. Added a few comments.
Functions, even marked public, cannot be exported and cannot be called from backend code (in Rust, C++, | ||
JS, etc.). Declare a [callback](callbacks.md) which can call the function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function can be called from backend code. (invoke_...)
The difference with callback is that they cannot be replaced with a callback handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, I had no idea! The SampleGeneratedComponent docs in Rust don't include a function, and neither the C++ nor the JS docs mention that :) I'll update those too, but in a separate PR to keep this one manageable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, your point about the difference between this and callbacks made me take a stab at a "functions vs callbacks" section, could you look over it and let me know if I got anything wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, falling function from native code is missing from that documentation 🙈
Functions, even marked public, cannot be exported and cannot be called from backend code (in Rust, C++, | ||
JS, etc.). Declare a [callback](callbacks.md) which can call the function. | ||
|
||
## Name resolution in function code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name resolution in function code is actually the same as in callback handler and property bindings (defined in #273 and arguably not well documented)
- function or callback arguments
- id of elements (including
self
,root
, andparent
) - property or model/index name in scope.
- imported enums or globals
- builtin namespaces (Math, Colors, Key)
- Return specific lookup depending on the return type of a function / callback, or the type of a property binding. If this is an enum, then enum names are in scope, if this is a brush or color, then the Colors namespace is in scope.
- Builtin functions (from Math or Colors namespace, or
debug
oranimation-tick
)
I don't think two sections for name resolution are required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, OK. I removed the second section. I think it would make sense to document this somewhere in the .slint docs to make it more discoverable -- of course it doesn't make sense to add it to the functions doc -- I'm thinking somewhere more specific, like a separate page under syntax? (then functions, callbacks, properties, etc. could all link to it). The github issue is very hard for anyone to discover :)
I can do that if you want (but also in a separate PR, keeping this one focused)
Thank you, please take another look 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
@tronical what do you think?
- Callback visiblity is always similar to `public` functions | ||
|
||
In general, the biggest reason to use callbacks is to be able to handle them from the backend code. If | ||
that is not needed, using a callback or a function is a matter of personal choice. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it's a matter of personal choice. If assigning a different handler is not needed, it's better to use a function than a callback.
(Function were introduced in a later version of Slint than callback, which is by maybe some example still use callback when they could have used functions)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of thought so myself, but didn't feel comfortable saying this without input from the core team. Updated to say "use a function" :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of suggestions inline. Overall I think this is an improvement, but I wouldn't have put so much emphasis on the lookup.
Similarly to other programming languages, functions in Slint are way to name, organize and reuse | ||
a piece of logic/code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that should be an adjective, not adverb?
Similarly to other programming languages, functions in Slint are way to name, organize and reuse | |
a piece of logic/code. | |
Similar to other programming languages, functions in Slint are way to name, organize, and reuse | |
a piece of logic/code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Functions can be defined as part of a component, or as part of an element within a component. Functions | ||
are always part of a component: it is not possible to declare global (top-level) functions, or to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the "Functions are always part of a component" bit is redundant.
Functions can be defined as part of a component, or as part of an element within a component. Functions | |
are always part of a component: it is not possible to declare global (top-level) functions, or to | |
Functions can be defined as part of a component, or as part of an element within a component. It is not possible to declare global (top-level) functions, or to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, good point.
declare them as part of a struct or enum. It is also not possible to nest functions within other | ||
functions. | ||
|
||
## Declaring a function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Match the first sentence, that uses plural. An alternative would be to use singular for both.
## Declaring a function | |
## Declaring functions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There are a lot of similarities between functions and [callbacks](callbacks.md): | ||
|
||
- They are both callable blocks of logic/code | ||
- They can be invoked similarly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't they invoked not only similarly, but in exactly the same way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done -- see, as someone just learning Slint, I'm a little bit afraid of making calls like that. As far as I know, they are, but I'm not an expert, so this was just me hedging 😛
- They can both have parameters and return values | ||
- They can both be declared `pure` | ||
|
||
But there are also key differences: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My immediate question here would be: If these are the key differences, where can I read about the remaining differences? I suggest to leave that out for now :)
But there are also key differences: | |
But there are also differences: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! (to be fair, "what else is different" is also a question I have and I honestly don't know the answer to it)
In general, the biggest reason to use callbacks is to be able to handle them from the backend code. If | ||
that is not needed, we recommend using a function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor simplification:
In general, the biggest reason to use callbacks is to be able to handle them from the backend code. If | |
that is not needed, we recommend using a function. | |
In general, the biggest reason to use callbacks is to be able to handle them from the backend code. Use | |
a function if that is not needed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
The lookup rules were quite surprising to me as someone unfamiliar with Slint, and I'd say they are not very typical. I can't, off the top of my head, remember another language that works this way. If there was a page describing the lookup rules in general (perhaps I'll try to add that based on @ogoffart's comment) then yeah, this could be simplified :) Thank you for the review 👍 -- let me know if anything else is needed before merging! |
While learning slint, I noticed that a lot of behaviors (in this case about functions) aren't clearly stated in the documentation. So I'm trying to document what I've learned and hopefully make it easier for the next person.
I've tested this mostly by experiment, meaning I'm not sure what's Working as Intended / by-design and what's Working as Implemented / by-chance. Actually that's a problem I'm hoping to address by documenting things more explicitly, but I need the core developers to tell me if something I've documented is not actually supposed to work that way.
Also, I don't know if you have specific standards/style regarding documentation that I should be following. If you do, let me know, I'm happy to read/apply them :)
There are more things I'd like to see in this file, in particular:
But I don't feel I know enough about these topics myself yet, so I'm starting with this.