W0063 - Mixed Strict and Relaxed Generators in Zip
Example
-module(example).
-export([test/0]).
%% List generators - mixed strict/relaxed
test_list() -> [Y || Y <- [a] && Y <:- [b]].
%% Map generators - mixed strict/relaxed
test_map(M1, M2) -> [{K1, K2} || K1 := V1 <- M1 && K2 := V2 <:- M2].
%% Binary generators - mixed strict/relaxed
test_binary() -> << <<X, Y>> || <<X>> <= <<1,2>> && <<Y>> <:= <<3,4>> >>.
%% Cross-type - list and map mixed
test_cross(List, Map) -> [{X, K} || X <- List && K := V <:- Map].
Explanation
Mixing strict generators (<:-, <:=) and relaxed generators (<-, <=)
within the same zip generator (&&) can lead to unexpected behavior, as the
semantics can differ between compiled modules and interpreted code (e.g., in the shell).
This applies to all generator types:
- List generators:
<-(relaxed) vs<:-(strict) - Binary generators:
<=(relaxed) vs<:=(strict) - Map generators:
K := V <-(relaxed) vsK := V <:-(strict)
See erlang/otp#9435 for an example of unexpected behavior when mixing generator types.
Recommended Fix
Use consistent generator types within the same zip generator:
%% All strict - behavior is well-defined
test_strict(M1, M2) -> [{K1, K2} || K1 := V1 <:- M1 && K2 := V2 <:- M2].
%% All relaxed - behavior is well-defined
test_relaxed(M1, M2) -> [{K1, K2} || K1 := V1 <- M1 && K2 := V2 <- M2].
%% Cross-type but consistent strictness - OK
test_cross_strict(List, Map) -> [{X, K} || X <:- List && K := V <:- Map].
Note: This diagnostic only applies to zip generators (&&).
Sequential/nested generators (comma-separated) are not affected.