-
Notifications
You must be signed in to change notification settings - Fork 7
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
Question: is it a normal practices to use global non-constant variables in Fyne apps #3
Comments
No you are quite right @dumblob the global was an oversight and has been fixed! You'll be pleased to know that there is indeed an upcoming API for handling data in the way you describe. https://github.com/fyne-io/7guis/blob/dataapi/counter/main.go |
@andydotxyz thanks for the quick reply and good news! That looks way closer to what I envisioned. Any plans for syntax sugar? I mean: count.SetInt(count.Value()+1) could be somehow shorter - in high-level languages it would probably be just an overloaded assignment: The following: cDeg := (valueF.Value() - 32) * (5.0 / 9.0)
valueC.SetFloat(cDeg) (from the temperature assignment) More importantly though, does widget.NewLabel("0").Bind(count), button) If I wanted to show count_tmp.SetString( fmt.Sprintf( "value %d is stored in count", count.Value() ) )
widget.NewLabel( "0" ).Bind( count_tmp ), button ) Another question would be regarding defaults - currently it seems a duplication is inevitable 😢: count := dataapi.NewInt(0)
...
widget.NewLabel("0").Bind(count), button) (see the Wow, sorry for bloating this thread - it just popped in my mind too quickly to not write it 😉. |
This is great feedback thanks, I will try and respond to some items and as there are things we could resolve will reopen the ticket until the design is enhanced. Syntactic sugar Filtering (formatting?) Defaults Copying in @steveoc64 as he is finalising the first dataapi at the moment. I think we should consider the defaults now, then review formatting options later as it's not the most common use-case. |
I meant it more generic - e.g. a label showing the counter with a given offset of 99 and twice as big (whereas other places reading count_tmp := dataapi.NewInt( 0 )
...
count_tmp.SetFloat( count.Value() * 2 + 99 )
widget.NewLabel( "0" ).Bind( count_tmp ), button ) (so it's not just about formatting - especially if the widget wouldn't eat String, but the original Int 😉 - imagine some range widgets or whatever) |
Hmm, I think I see your point - but I don't know how frequently developers will want to show a value that is not representative of the value stored. The OnChanged callback can be used on the situations that people want to do something custom... |
It's subjective, but I use it a lot 😉. The point is, that the data are usually by far not prepared for presentation due to coupling (the data are e.g. big lists of structs or some trees or hash maps or bitmaps etc.) and one needs only certain pieces of them (e.g. just part of the picture or just two records from the huge list etc.). Therefore I called it "filtering" (or "windowing" or alike). In other words, the raw/source data are usually not in the form the widget needs them to be (widget needs e.g. some widget-specific struct describing richt text, but the data are stored in memory and/or DB in very different formats because of space and speed constraints). This is historically one of the most painful stuff about UI - that one needs to adapt the data too much throughout the whole app just to match the last layer - UI. But that's usually nonsense and therefore there are ever-emerging new UI libs trying to solve it, but the point is, that the data should not follow UI, but UI should follow the data 😉 (i.e. first at the very last step, which is pure presentation, should be the data reordered, decoupled or (re)coupled). |
Good points. However what you are currently seeing is just primitive values binding - not a map or a list. These will need to provide more complex behaviours as you say. Our expectation is that the data source providers will have to do translation into a data descriptor that binds well to the UI. For example a database data source may exist where you filter or select and then the resulting data "map" for each item in a list would extract the data from the record to display that will then map cleanly to widgets etc. Does this help? |
Maybe I misunderstood, but are you describing a process which demands to change the data representation to the by Fyne required types sooner than at the place of widget declaration/definition? If so, then no, the use case is, that one e.g. fetches data from DB(s), then works with them (incl. e.g. saving different parts of them back to DB) and then presents yet different parts of them in different parts of UI. And it absolutely doesn't make any sense to prepare the data for the UI e.g. already during the "working with them" as it's inefficient (usually the "working with them" runs separately from UI and at different "frequencies" - i.e. UI is to reflect just some samples of all the frequent changes of the data) and demands spaghetti code style or at least increased verbosity at unrelated places. Does that make more sense? |
I think we are talking about the same thing, but it's tough to say without more concrete examples which will come with time. You can have many layers of data management behind this if you want :) I hope that what I am describing could function as the filtering you describe. What we are looking at now is the last step in presenting as they are trivial examples - data from structs etc will require an additional "layer" which is being developed as part of this API. I will try to get an example up here soon as, for example, CRUD will need that if not others. |
I agree. Code would be the best tool to showcase that. I'll wait until the API for structs will be sketched and then raise my hand if I'll observe something suspicious 😄. Thanks for the great work and willingness to listen to others (that's a very valuable thing in open source!). |
Great. And thank you for the input - we couldn't build it without hearing what people like or don't about the designs (both ours and that of others ;) ). |
Subbed to thread. Great thread, more more more ! Not much time this morning - coffee, then off to work, so more later. Couple of small points worth pondering in the meantime :
so
Will produce a label with the "100" displayed. Inside Bind() it does call SetText() with the bound value. It does mean that the initial string passed in NewLabel() gets thrown away ... so there is some inefficiency there, but no need for redundancy. Computed props - yep, I see what you are saying there. Keeping in mind that we are operating in a compiled environment here, so expression evaluation either needs to be added (ie - adding an expression interpreter ?), or using functions. So something like this :
^^ Thats not there yet, and wont be part of the next release, but thats a general idea for computed props that dont need an expression interpreter. Would be fun to do. Thats within reach, because BindFunc(dataItem, funcPtr) has enough info to know that it needs to register a listener on the dataItem, and enough info to know the type returned by the function, and how to convert it into the type needed for the widget (a string in this case, but it depends entirely on the widget) There are many other properites of widgets that it would be good to bind to data values too - ie, Enable/Disable based on an expression, etc etc. |
The expression interpreter is probably not needed due to function literals ("anonymous functions" or "lambdas" or "callbacks with current values") Go supports and which can be passed "in place" to
Yep, this will be needed to be supported. |
We now have the starts of data binding work on Fyne
Hopefully that supports some of the discssions above and is certainly extensible :) |
@andydotxyz great, that looks promising! Do you plan to generalize it a bit (e.g. by employing synchronous programming as in S as the seemingly least friction approach)? (take this question with a grain of salt as I didn't dive into the data API) |
I think that what we are working on provides the flexibility that S is also striving for. |
I am going to close this issue as the version of data binding on
|
Thanks @andydotxyz, that's good news. Need to try it soon after it'll be released as stabilized. |
I'm quite surprised by the first
counter
example - namely about the way how the state is being stored and mutated. I'm pretty sure globals are not the standard practice, so I assume one would normally use a local variable in themain()
scope.But the point is, that I'd be also quite surprised if Fyne didn't provide a way to store the mutable state (in this case just an integer) in a more "reactive" manner (e.g. in some "reactive" wrapper which when written to - possibly even from a different go routine - would automagically update all the widgets which read from the "reactive" wrapper instance in their callback).
Does Fyne provide a better support for "live" data (i.e. "reactiveness") than using such plain "global" variables?
The text was updated successfully, but these errors were encountered: