jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.33k stars 1.62k forks source link

Stack Overflow when modifying RxSet in listener #2517

Open Andrflor opened 2 years ago

Andrflor commented 2 years ago

Describe the bug If i try to empty a RxList from a debounce it works perfectly. When I try the exact same code with RxSet it throws a stack overflow. It was working perfectly on GetX <5.0.0

Reproduction code

void main() => runApp(MaterialApp(home: Home()));

class Home extends StatelessWidget {
  final rxSet = <String>{}.obs;

  Home() {
    debounce(rxSet, (Set<String> value) {
      if (value.isNotEmpty) {
        // This is causing stack overflow
        rxSet({});
      }
    });
  }

  @override
  Widget build(context) => Scaffold(
      appBar: AppBar(title: Text("Set")),
      body: Center(
        child: Obx(() => Text("$rxSet")),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          // We add an element to the set
          rxSet.addAll({'a'});
          // Calling this with a non empty iterable will also trigger the overflow
          rxSet.addAll({});
        },
      ));
}

It's working perfectly with RxList

  final rxSet = <String>[].obs;

  Home() {
    debounce(rxSet, (List<String> value) {
      if (value.isNotEmpty) {
        // This is NOT causing stack overflow
        rxSet([]);
      }
    }

To Reproduce Steps to reproduce the behavior:

  1. Click the button
  2. See the overflow in console

Expected behavior No overflow this should having the same behavior with list

Flutter Version: 3.0.5

Getx Version: 5.0.0-beta.52

Describe on which device you found the bug: All

Minimal reproduce code

final rxSet = <String>{}.obs;
debounce(rxSet, (Set<String> value) {
  if (value.isNotEmpty) {
    // This is causing stack overflow
    rxSet({});
  }
});
rxSet.addAll({'a'});
rxSet.addAll({});

Error

[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: Stack Overflow
#0      ListMixin.contains (dart:collection/list.dart:124:3)
#1      ListNotifierSingleMixin.containsListener (package:get/get_state_manager/src/simple/list_notifier.dart:37:23)
#2      Notifier.read (package:get/get_state_manager/src/simple/list_notifier.dart:181:40)
#3      ListNotifierSingleMixin.reportRead (package:get/get_state_manager/src/simple/list_notifier.dart:54:23)
#4      GetListenable.value (package:get/get_state_manager/src/rx_flutter/rx_notifier.dart:133:5)
#5      RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:31:9)
#6      RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#7      RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#8      RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#9      RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#10     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#11     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#12     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#13     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#14     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#15     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#16     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#17     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#18     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#19     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#20     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#21     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#22     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#23     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#24     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#25     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#26     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#27     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#28     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#29     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#30     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#31     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#32     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#33     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#34     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#35     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#36     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#37     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#38     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#39     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#40     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#41     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#42     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
#43     RxSet.value= (package:get/get_rx/src/rx_types/rx_iterables/rx_set.dart:32:5)
...
...
#114512 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#114513 _FutureListener.handleValue (dart:async/future_impl.dart:147:18)
#114514 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:766:45)
#114515 Future._propagateToListeners (dart:async/future_impl.dart:795:13)
#114516 Future._completeWithValue (dart:async/future_impl.dart:566:5)
#114517 _completeOnAsyncReturn (dart:async-patch/async_patch.dart:264:13)
#114518 GetHttpClient.post (package:get/get_connect/http/src/http.dart)
#114519 _rootRunUnary (dart:async/zone.dart:1434:47)
#114520 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#114521 _FutureListener.handleValue (dart:async/future_impl.dart:147:18)
#114522 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:766:45)
#114523 Future._propagateToListeners (dart:async/future_impl.dart:795:13)
#114524 Future._completeWithValue (dart:async/future_impl.dart:566:5)
#114525 _completeOnAsyncReturn (dart:async-patch/async_patch.dart:264:13)
#114526 GetHttpClient._performRequest (package:get/get_connect/http/src/http.dart)
#114527 _rootRunUnary (dart:async/zone.dart:1434:47)
#114528 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#114529 _FutureListener.handleValue (dart:async/future_impl.dart:147:18)
#114530 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:766:45)
#114531 Future._propagateToListeners (dart:async/future_impl.dart:795:13)
#114532 Future._completeWithValue (dart:async/future_impl.dart:566:5)
#114533 _completeWithNoFutureOnAsyncReturn (dart:async-patch/async_patch.dart:277:13)
#114534 GetModifier.modifyResponse (package:get/get_connect/http/src/interceptors/get_modifiers.dart)
#114535 _rootRunUnary (dart:async/zone.dart:1434:47)
#114536 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#114537 _FutureListener.handleValue (dart:async/future_impl.dart:147:18)
#114538 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:766:45)
#114539 Future._propagateToListeners (dart:async/future_impl.dart:795:13)
#114540 Future._completeWithValue (dart:async/future_impl.dart:566:5)
#114541 Future._asyncCompleteWithValue.<anonymous closure> (dart:async/future_impl.dart:639:7)
#114542 _rootRun (dart:async/zone.dart:1426:13)
#114543 _CustomZone.run (dart:async/zone.dart:1328:19)
#114544 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#114545 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#114546 _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
#114547 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
qcks commented 2 years ago

you

get a => b;
get b => a;
Andrflor commented 2 years ago

No... @qcks Maybe you need glasses...

Let me help you

  if (value.isNotEmpty) {

See? There is a condition that should not be triggered... The problem is that isNotEmpty is returning false when it should return true...

Furthermore I stated a lot more info, like the fact that the code was working perfectly before upgrading to 5.0.0 I also stated that the same code works perfectly with RxList instead of RxSet...

Please read posts carefully before answering, otherwise it's just a total time waste.

qcks commented 2 years ago

@Andrflor too young; example.