Make fill-in-the-blank code questions corresponding to the following text.:
GUI development with Rust and GTK 4

Memory Management
A GObject (or glib::Object in Rust terms) is a reference-counted, mutable object. Let’s see in a set of real life examples which consequences this has.

fn main() -> glib::ExitCode {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();

// Connect to “activate” signal of app
app.connect_activate(build_ui);

// Run the application
app.run()
}

fn build_ui(application: &Application) {
// Create two buttons
let button_increase = Button::builder()
.label(“Increase”)
.margin_top(12)
.margin_bottom(12)
.margin_start(12)
.margin_end(12)
.build();
let button_decrease = Button::builder()
.label(“Decrease”)
.margin_top(12)
.margin_bottom(12)
.margin_start(12)
.margin_end(12)
.build();

// A mutable integer
let mut number = 0;

// Connect callbacks
// When a button is clicked, number should be changed
button_increase.connect_clicked(|| number += 1);
button_decrease.connect_clicked(|| number -= 1);

// Add buttons to gtk_box
let gtk_box = gtk::Box::builder()
.orientation(Orientation::Vertical)
.build();
gtk_box.append(&button_increase);
gtk_box.append(&button_decrease);

// Create a window
let window = ApplicationWindow::builder()
.application(application)
.title(“My GTK App”)
.child(&gtk_box)
.build();

// Present the window
window.present();
}
Here we would like to create a simple app with two buttons. If we click on one button, an integer number should be increased. If we press the other one, it should be decreased. The Rust compiler refuses to compile it though.

For once the borrow checker kicked in:

error[E0499]: cannot borrow number as mutable more than once at a time
--> main.rs:27:37
|
26 | button_increase.connect_clicked(|| number += 1);
| ------------------------------------------------
| | | |
| | | first borrow occurs due to use of number in closure
| | first mutable borrow occurs here
| argument requires that number is borrowed for 'static
27 | button_decrease.connect_clicked(|| number -= 1);
| ^^^ ------ second borrow occurs due to use of number in closure
| |
| second mutable borrow occurs here
Also, the compiler tells us that our closures may outlive number:


error[E0373]: closure may outlive the current function, but it borrows number, which is owned by the current function
--> main.rs:26:37
|
26 | button_increase.connect_clicked(|| number += 1);
| ^^^ ------ number is borrowed here
| |
| may outlive borrowed value number
|
note: function requires argument type to outlive 'static
--> main.rs:26:5
|
26 | button_increase.connect_clicked(|| number += 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of number (and any other referenced variables), use the move keyword
|
26 | button_increase.connect_clicked(move || number += 1);
| ^^^^^^^^
Thinking about the second error message, it makes sense that the closure requires the lifetimes of references to be 'static. The compiler cannot know when the user presses a button, so references must live forever. And our number gets immediately deallocated after it reaches the end of its scope. The error message is also suggesting that we could take ownership of number. But is there actually a way that both closures could take ownership of the same value?

Yes! That is exactly what the Rc type is there for. The Rc counts the number of strong references created via Clone::clone and released via Drop::drop, and only deallocates it when this number drops to zero. We call every object containing a strong reference a shared owner of the value. If we want to modify the content of our Rc, we can use the Cell type.

The Cell class is only suitable for objects that implement the Copy trait. For other objects, RefCell is the way to go. You can learn more about interior mutability in this section of the book Rust Atomics and Locks.

Filename: listings/g_object_memory_management/1/main.rs

// Reference-counted object with inner-mutability
let number = Rc::new(Cell::new(0));

// Connect callbacks, when a button is clicked number will be changed
let number_copy = number.clone();
button_increase.connect_clicked(move || number_copy.set(number_copy.get() + 1));
button_decrease.connect_clicked(move || number.set(number.get() - 1));
It is not very nice though to fill the scope with temporary variables like number_copy. We can improve that by using the glib::clone! macro.

Filename: listings/g_object_memory_management/2/main.rs

button_increase.connect_clicked(clone!(@strong number => move || {
number.set(number.get() + 1);
}));
button_decrease.connect_clicked(move || {
number.set(number.get() - 1);
});
Just like Rc<Cell<T>>, GObjects are reference-counted and mutable. Therefore, we can pass the buttons the same way to the closure as we did with number.

Filename: listings/g_object_memory_management/3/main.rs

// Connect callbacks
// When a button is clicked, number and label of the other button will be changed
button_increase.connect_clicked(clone!(@weak number, @strong button_decrease =>
move || {
number.set(number.get() + 1);
button_decrease.set_label(&number.get().to_string());
}));
button_decrease.connect_clicked(clone!(@strong button_increase =>
move || {
number.set(number.get() - 1);
button_increase.set_label(&number.get().to_string());
}));
If we now click on one button, the other button’s label gets changed.

But whoops! Did we forget about one annoyance of reference-counted systems? Yes we did: reference cycles. button_increase holds a strong reference to button_decrease and vice-versa. A strong reference keeps the referenced value from being deallocated. If this chain leads to a circle, none of the values in this cycle ever get deallocated. With weak references we can break this cycle, because they don’t keep their value alive but instead provide a way to retrieve a strong reference if the value is still alive. Since we want our apps to free unneeded memory, we should use weak references for the buttons instead.

Filename: listings/g_object_memory_management/4/main.rs

// Connect callbacks
// When a button is clicked, number and label of the other button will be changed
button_increase.connect_clicked(clone!(@weak number, @weak button_decrease =>
move || {
number.set(number.get() + 1);
button_decrease.set_label(&number.get().to_string());
}));
button_decrease.connect_clicked(clone!(@weak button_increase =>
move |_| {
number.set(number.get() - 1);
button_increase.set_label(&number.get().to_string());
}));
The reference cycle is broken. Every time the button is clicked, glib::clone tries to upgrade the weak reference. If we now for example click on one button and the other button is not there anymore, the callback will be skipped. Per default, it immediately returns from the closure with () as return value. In case the closure expects a different return value @default-return can be specified.

Notice that we move number in the second closure. If we had moved weak references in both closures, nothing would have kept number alive and the closure would have never been called. Thinking about this, button_increase and button_decrease are also dropped at the end of the scope of build_ui. Who then keeps the buttons alive?

Filename: listings/g_object_memory_management/4/main.rs

// Add buttons to gtk_box
let gtk_box = gtk::Box::builder()
.orientation(Orientation::Vertical)
.build();
gtk_box.append(&button_increase);
gtk_box.append(&button_decrease);
When we append the buttons to the gtk_box, gtk_box keeps a strong reference to them.

Filename: listings/g_object_memory_management/4/main.rs

// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title(“My GTK App”)
.child(&gtk_box)
.build();
When we set gtk_box as child of window, window keeps a strong reference to it. Until we close the window it keeps gtk_box and with it the buttons alive. Since our application has only one window, closing it also means exiting the application.

As long as you use weak references whenever possible, you will find it perfectly doable to avoid memory cycles within your application. Without memory cycles, you can rely on GTK to properly manage the memory of GObjects you pass to it.