Skip to main content

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) vs K := V <:- (strict)

See erlang/otp#9435 for an example of unexpected behavior when mixing generator types.

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.