How to get previous value from gtk-notify-signal handler? - gtk

For example,
g_signal_connect(G_OBJECT(window), "notify::title", G_CALLBACK(onTitleChanged), NULL);
void onTitleChanged(GtkWidget* widget,
GParamSpec* property,
gpointer data)
{
g_message("%s is changed, the new value is %s\n", property->name, gtk_window_get_title(GTK_WINDOW(widget)));
}
How could I get the previous(old) title value inside the notify-signal handler(onTitleChanged) ?
Thanks.

That is not available from GObject so you'll have to cache the current value in in your app.
The safe way to do that is to update the cached value in the end of your notify handler -- but depending on your uses you may also need to initialize the value (and must of course remember to allocate/free when necessary if the value is a string).

Related

Why can't I use local variable in a callback?

Let's say I've a stream() which returns Stream<int>. stream().listen returns StreamSubscription.
var subs = stream().listen((e) {
if (someCondition) subs.cancel(); // Error
});
I don't understand why is there an error, because by the time I start listening for events in the listen method, I would have definitely a valid object subs.
Note: I know this can be done by creating a StreamSubscription instance/top-level variable but why they have prevented the use of local variable like this?
We know that Stream.listen does not call its callback until after a value is returned, but the Dart compiler does not.
Consider the following function, which simply calls a callback and returns the result:
T execute<T>(T Function() callback) => callback();
Now, consider using it to assign a variable:
int myVariable = execute(() => myVariable + 1);
The problem here is that the given callback is called synchronously, before myVariable is assigned, but it tries to use myVariable to calculate a value!
To resolve this issue with your stream question, you can use the new late keyword. Using late tells the compiler that you know the variable will be assigned by the time it's accessed.
late final StreamSubscription<MyType> subscription;
subscription = stream().listen(/* ... */);
Likely because it's possible that subs will be used before it's assigned. We know that the callback passed to listen will be called on stream events, but it's also possible that the callback is called immediately and it's return value or a calculation done by it may be required for the return value of the function it was passed to.
Take this fakeFunc for instance, which I made an extension on the int class for convenience:
extension FakeListen on int {
int fakeFunc(int Function(int x) callback, int val) {
return callback(val);
}
}
The return value depends on the result of callback!
int subs = x.fakeFunc((e) {
print(e);
subs.toString();//error
return e + 1;
}, 5);
I can't use subs because subs will be guaranteed to not be exist at this point. It's not declared. This can be easily solved by moving the declaration to a separate line, but also forces you to make it nullable. Using late here won't even help, because subs won't exist by the time you try to use it in the callback.
Your scenario is different, but this is an example of where allowing that would fail. Your scenario involves a callback that is called asynchronously, so there shouldn't be any issues with using subs in the callback, but the analyzer doesn't know that. Even async-marked methods could have this issue as async methods run synchronously up until its first await. It's up to the programmer to make the right decision, and my guess is that this error is to prevent programmers from making mistakes.

Is Dart pass by reference? [duplicate]

This question already has answers here:
What is the true meaning of pass-by-reference in modern languages like Dart?
(3 answers)
Closed 1 year ago.
In this post: Flutter video_player dispose
I asked how to dispose something so I can re-use it again. The answer provided works correctly but it left me with this question:
why does this code work as intended? eg it disposes the old instance from videoController using oldController
final oldController = videoController;
WidgetsBinding.instance.addPostFrameCallback((_) async {
await oldController.dispose();
_initController(link); //contains reassignment of videoController = VideoController.network(...)
});
in C or similar languages, a use of pointer is needed (or should I say my preferred way). To pass the reference, assign a new value to it and then take care of the old one.
Sorry that my answer left you with a confusion. Yes, in Dart you work with references to objects, just like in Java. I'll give a short example that should make it clear for you why this code works as intended:
void main() {
final t = Test(Test());
t.removeField();
}
class Test {
Test t;
Future<void> removeField() async {
print('current field: $t');
Future.delayed(Duration(seconds: 2)).then((_) => print('delayed value: $t'));
t = null;
}
Test([this.t]);
}
prints:
current field: Instance of 'Test'
delayed value: null
In this case, field's value is set to null first and then 2 seconds later callback executes. It accesses object's field, but it's already null. But if we make it like this:
final old = t;
Future.delayed(Duration(seconds: 2)).then((_) => print('delayed value: $old'));
it prints:
current field: Instance of 'Test'
delayed value: Instance of 'Test'
We stored previous value of the field and passed it to the callback, so it won't access nulled field.
Dart does not support passing by reference. Dart is only passed by value, just like Java. Java also does not support reference passing.
Is Java “pass-by-reference” or “pass-by-value”?
https://stackoverflow.com/a/40523/1737201
Below is a little proof.
void main() {
// The variable "myVar" is a "lvalue" (storage of value)
// Now we assign the value to "myVar" via "rvalue" "Object()"
final myVar = Object();
// Remember the old value
final oldObject = myVar;
// Now we will try to pass by reference.
// We assume that we will pass the reference of storage ("lvalue")
// ("myVar" im our case) because we cannot reference the value (pure data)
// because the value does not contain storage location information.
tryChangeMyVarByRef(myVar);
// Check the result passing by reference
// If storage of value was passed by its reference then changing
// the value in this storage should have effect.
assert(!identical(myVar, oldObject));
// Epic fail because Dart does not support pass by refernce.
print('WOW, it works!');
}
void tryChangeMyVarByRef(Object referencedStorgeOfValue) {
// Try change the value stored in referenced storage of value
referencedStorgeOfValue = Object();
}
EDIT:
The value (or more correct rvalue which means a data whitout any storage) cannot have an address because the value is just a data. In programming impossible to reference the data (because there are no any way to do that) but possible to reference the storage of data (eg. address of variable) because the storage are always has some location rather than data (data only can be stored at some location but not referenced because data can be replaced at any time at this location and thus this cannot be called as reference to data because this can be incorrect after data reassigment would be perfomed but should be only called as reference of some storage of some data).
In the programming the term "pass by reference" means: pass the reference (address of the location) of the value storage (that is, the address of some varibale with any data but not the address of this data).
This allows to replace (but not just change) stored data at some location becuase the storage was referenced (address of laocation was known).
Which means only one thing: you pass reference of the variable where some value are stored.
And this does not means the reference of some value as many newbie wrongly think (who never used C or C++ language).
Another important thing is that the in Dart the object (or instances) itself are references because they are boxed (the values was stored in the heap).
This creates illusion that you pass by reference but at the same time you pass by value the reference (where reference as value is passed by value). Pass by value the reference is not the same as pass by reference the reference.
Free advice to newbie: Learn the C or C++ programming languages to find out the difference between the following things:
Pass by value the reference
Pass by reference the reference
In both cases the value itself is a reference but in first case you pass the value (reference) by value but in second case you pass the value (reference) by reference.
Enjoy!

What event fires after .Load in Codefluent?

I want to store an initial value when an object is loaded in a private property. If I change the value later on I want to be able to compare the initial and the current value. I can't find a suitable event for capturing the initial value. Should be just after loading the object... OnAfterCreate does not do the trick..
I could propably also use the PropertyChanged event but I am not sure how to implement it..
It was OnAfterReadRecord indeed. Thanks Simon!
protected void OnAfterReadRecord(System.Data.IDataReader reader,
CodeFluent.Runtime.CodeFluentReloadOptions options)
{
_initialActive = CodeFluentPersistence.GetReaderValue(reader, "CwObject_Active",
((bool)(false)));
}

Change G_PARAM_CONSTRUCT_ONLY property via inheritance

I try to inherit a gobject and, among other things, would like to change the value of a G_PARAM_CONSTRUCT_ONLY property so the next child class doesn't have to care.
Here's an example to depict this: GtkComboBox has a construct only property called "has-entry" with default value FALSE. In class A I want to change this value to TRUE, so that class B doesn't need to care.
GtkComboBoxClass <-- AClass <-- BClass
"has-entry" FALSE TRUE
The first naive approach was to use g_object_set() in A's instance_init function, but to no avail.
The next idea was to obtain the GParamSpec with g_object_class_find_property() and change the default value with g_param_value_set_default() in A's class_init function. But I suppose this to change the default for all GtkComboBoxClass derived objects.
The best idea I could come up with: If g_object_class_override_property() creates a new GParamSpec I could find this and set its default value in A's class_init function. But documentation doesn't loose a word about this.
So my question: Is this a working, and intended, way of accomplishing this, or is there a better solution?
Tried so far:
g_object_set() in instance init():
no warning on start
no effect
g_object_set() in GObjectClass->constructor():
no warning on start
no effect
warning on exit: invalid cast from GtkCellCiew to GtkEntry
g_object_set() in GObjectClass->constructed():
warning on start: can't be set after construction
Thanks
Stefan
if you want to set a property in a sub-class, and that property is construct-only, then you should use the constructed virtual function to call g_object_set() instead of the init virtual.
properties marked as construct-only will be applied during construction, using their default value, unless specified on the constructor itself — i.e. with g_object_new(). this means that setting a construct-only property inside init() will not suffice, as the value will be set after init() has been called. the constructed() virtual function, on the other hand, is called after the constructor properties have been applied, so it's possible to override the default value there.
Answering this for myself:
A look into gobject source reveals that the properties list given to constructor() contains all G_PARAM_CONSTRUCT and G_PARAM_CONSTRUCT_ONLY properties and their default or given values.
Modifying these values is undocumented (or at least I couldn't find it), but it works.
Construction time property values have to be modified in this list before chaining up to parents constructor, non construct properties have to be set afterwards. Example code looks like:
static GObject *constructor(GType gtype, guint n_properties, GObjectConstructParam *properties) {
GObject *object;
guint i;
gchar const *name;
GObjectConstructParam *property;
for (i = 0, property = properties; i < n_properties; ++i, ++property) {
name = g_param_spec_get_name(property->pspec);
if (!strcmp(name, "has-entry")) // is G_PARAM_CONSTRUCT_ONLY
g_value_set_boolean(property->value, TRUE);
}
object = G_OBJECT_CLASS(parent_class)->constructor(gtype, n_properties, properties);
g_object_set(object, "entry-text-column", TEXT_COLUMN, NULL);
return object;
}

Is it bad practice to have my getter method change the stored value?

Is it bad practice to change my getter method like version 2 in my class.
Version 1:
public String getMyValue(){
return this.myValue
}
Version 2:
public String getMyValue(){
if(this.myValue == null || this.myValue.isEmpty()){
this.myValue = "N/A";
}
return this.myValue;
}
I think it is actually quite a bad practice if your getter methods change the internal state of the object.
To achieve the same I would suggest just returning the "N/A".
Generally speaking this internal field might be used in other places (internally) for which you don't need to use the getter method. So in the end, the call to foo.getMyValue() could actually change the behaviour of foo.
Alternatively, the translation from null to "N/A" could be done in the setter, i.e. the internal value could be set to "N/A" if null is passed.
A general remark:
I would only add states such as "N/A" if they are expected by some API or other instance relying on your code. If that is not the case you should rely on the standard null types that are available to you in your programming language.
In my opinion, unless you are doing lazy-loading (which you are not in that case), getters should not change the value. So I would either:
Put the change in the setter
public void setMyValue(String value) {
if(value == null || value.isEmpty()){
this.myValue = "N/A";
} else {
this.myValue = value;
}
}
Or make the getter return a default value if value not set properly:
public String getMyValue() {
if(this.myvalue == null || this.myvalue.isEmpty()){
return "N/A";
}
return this.myValue;
}
In the case of lazy-loading, where I would say that changing your members in a getter is fine, you would do something like:
public String getMyValue() {
if (this.myvalue == null) {
this.myvalue = loadMyValue();
}
return this.myValue;
}
No. You're doing two things here. Getting and setting.
Yes. It's a bad practice.
Why?
When the value is set (in a constructor or setter method), it should be validated, not when a getter method is called. Creating a private validate* method for this is also a good idea.
private boolean validateThisValue(String a) {
return this.myValue != null && !this.myValue.isEmpty();
}
public void setThisValue(String a) {
if (validateThisValue(a)) {
this.myValue = a;
}
else {
// do something else
// in this example will be
this.myValue = "N/A";
}
}
And, in the getter method, never ever change the state of the object. I have worked on some projects, and the getter often must be made const: "this method cannot change internal state".
At least, if you do not want to complicate things, in the getter method, you should return "N/A" rather than change internal state and set myValue to "N/A".
I usually define a specific getter.
Never alter original getter:
public String getMyValue(){
return this.myValue
}
And create a specific getter:
public String getMyValueFormatted(){
if(this.myvalue == null || this.myvalue.isEmpty()){
return "N/A";
}else{
return this.myValue;
}
}
I think it's better to initialize this.myValue = "N/A". And subsequent calls to setMyValue should modify the this.myValue according to your business conditions.
The getMyValue shouldn't modify in any way this.myValue. If your needs are to return a certain value, you should return that value (like "N/A") and not alter this.myValue . Getters must not modify member's value.
I would change better the setter method so, if the value is null or empty, the N/A is assigned to the attribute. So, if you use the attribute in other methods inside the class (v.g. toString()) you will have the intended value there.
Alternatively, change the setter method to launch an exception when the value being set is not right, so the programmer is forced to improve its handling prior to setting the value.
Other than that, it is ok.
I do feel this is a bad practice unless and until you explain the reason why it is so necessary for you modify the object inside the getter method instead of doing it inside the setter method.
Do you feel this cannot be done for some reason? Could you please elaborate?
Do what ever you like. After all getters and setters are just another public methods. You could use any other names.
But if you use frameworks like Spring, you are bound to use those standard names and you should never put your custom codes inside them.
absolutely yes, it's a bad pratice.
Imagine you communicate accross network with a third party (remoting, COM, ...), this will increase the round-trip and then hit application performance.
A setter could modify as part of validation, but a getter should return the value and let the validation be done by the caller. If you do validate, then how should be documented.
This actually highly depends on the contract you want to enforce with your get()-method. According to design-by-contract conventions the caller has to make sure that the preconditions are met (which means doing a validation in a setter method often is actually bad design) and the callee (I do not know if that's the correct english term for that, i.e., the called one) makes sure that the post conditions are met.
If you define your contract so that the get()-method is not allowed to change the object then you are breaking your own contract. Think about implementing a method like
public isValid() {
return (this.myvalue == null || this.myvalue.isEmpty());
}
Advantage of this approach is that you do not have to check wether the return of your get() is "N/A" or something else. This also can be called before calling set() to validate that you do not insert illegal values into your object.
If you want to set a default value you should do that during initialization.
State changes in getters should be a hanging offence. It means that client code must be careful about the order in which it accesses getters and setters and to do this it must have knowledge of the implementation. You should be able to call the getters in any order and still get the same results. A related problem occurs when the setter modifies the incoming value depending on the current state of the object.
You can use some value holder for this purpose. Like Optional class in guava library.