diff --git a/blog/2024/05/14/laminar-v17.0.0.html b/blog/2024/05/14/laminar-v17.0.0.html index 131df13..de0eefb 100644 --- a/blog/2024/05/14/laminar-v17.0.0.html +++ b/blog/2024/05/14/laminar-v17.0.0.html @@ -143,8 +143,18 @@
flatMap
does not cause glitches on its own. It can only cause glitches when it's used unnecessarily, and even then, only under certain conditions. When flatMap
is used by true necessity, the observable graph is pretty much always structured in such a way that a glitch can't possibly happen (simplifying a bit here, but it really does work like that. Airstream docs about transactions, topological rank, and loopy vs flowy operators explain all that in more detail).
Unfortunately, with flatMap
being such a common operation on many data types, developers tend to reach for it before they learn about why it's a bad idea in Airstream, and many never read the entirety of the documentation – which does explain the undesirable characteristics of flatMap
in great detail. And so, they end up using flatMap
in a way that is unnecessary, and can thus cause FRP glitches.
Most of the problem with flatMap
is its very inviting / innocuous name, as well as Scala's for-comprehensions using it invisibly under the hood, resulting in developers using it on autopilot. And so, to improve the user experience, especially for non-experts, the method called flatMap
on Observables is now renamed into several variants, such as flatMapSwitch
, flatMapMerge
, and flatMapCustom
. It is thus no longer available via for-comprehensions.
Of the new operators, flatMapSwitch
is the "standard" one that matches the default behaviour of flatMap
.
Similar changes apply to the flatten
operator, of course.
See the rewritten Flattening Observables section of Airstream docs.
+++UPDATE: I would like to emphasize that using
+flatMap
(nowflatMapSwitch
) to get async events is perfectly fine. To put it simply, the concept of glitches basically does not apply to observables that emit their events asynchronously. So you can safely useflatMapSwitch
to get e.g. network responses:
// This is fine.
+val userS: Signal[User] = ???
+val responseS: EventStream[Response] = userS.flatMapSwitch { user =>
+ FetchStream.get(s"/user/${user.id}")
+}
+
Migration:
flatMap
usage, and import FlattenStrategy.flatMapAllowed
as necessary, to make your code compile as-is.flatMap
does not cause glitches on its own. It can only cause glitches when it's used unnecessarily, and even then, only under certain conditions. When flatMap
is used by true necessity, the observable graph is pretty much always structured in such a way that a glitch can't possibly happen (simplifying a bit here, but it really does work like that. Airstream docs about transactions, topological rank, and loopy vs flowy operators explain all that in more detail).
Unfortunately, with flatMap
being such a common operation on many data types, developers tend to reach for it before they learn about why it's a bad idea in Airstream, and many never read the entirety of the documentation – which does explain the undesirable characteristics of flatMap
in great detail. And so, they end up using flatMap
in a way that is unnecessary, and can thus cause FRP glitches.
Most of the problem with flatMap
is its very inviting / innocuous name, as well as Scala's for-comprehensions using it invisibly under the hood, resulting in developers using it on autopilot. And so, to improve the user experience, especially for non-experts, the method called flatMap
on Observables is now renamed into several variants, such as flatMapSwitch
, flatMapMerge
, and flatMapCustom
. It is thus no longer available via for-comprehensions.
Of the new operators, flatMapSwitch
is the "standard" one that matches the default behaviour of flatMap
.
Similar changes apply to the flatten
operator, of course.
See the rewritten Flattening Observables section of Airstream docs.
+++UPDATE: I would like to emphasize that using
+flatMap
(nowflatMapSwitch
) to get async events is perfectly fine. To put it simply, the concept of glitches basically does not apply to observables that emit their events asynchronously. So you can safely useflatMapSwitch
to get e.g. network responses:
// This is fine.
+val userS: Signal[User] = ???
+val responseS: EventStream[Response] = userS.flatMapSwitch { user =>
+ FetchStream.get(s"/user/${user.id}")
+}
+
Migration:
flatMap
usage, and import FlattenStrategy.flatMapAllowed
as necessary, to make your code compile as-is.