Problem using setelement tail recursive function
- Erlang R23 + version has problems
- Fixed on 2022-03-28 fixed
Test
-module(setelement_test).
-export([
test_a/2,
test_b/2,
test_c/2,
test_d/2,
test/0
]).
-record(r_element, {key1, key2, key3}).
test_a([], Element) -> Element;
test_a([{Index, AddVal} | T], Element) ->
#r_element{} = Element,
OldVal = element(Index, Element),
Element2 = setelement(Index, Element, OldVal + AddVal),
test_a(T, Element2).
test_b([], Element) -> Element;
test_b([{Index, AddVal} | T], Element) ->
OldVal = element(Index, Element),
Element2 = setelement(Index, Element, OldVal + AddVal),
test_b(T, Element2).
test_c([], Element) -> Element;
test_c([{IndexName, AddVal} | T], Element) ->
#r_element{} = Element, %% diff and test_d
Element2 =
case to_index(IndexName) of
Index when Index > 0 ->
OldVal = element(Index, Element),
setelement(Index, Element, OldVal + AddVal); %% {call_ext_last,3,{extfunc,erlang,setelement,3},3},
0 ->
Element
end,
test_c(T, Element2).
test_d([], Element) -> Element;
test_d([{IndexName, AddVal} | T], Element) ->
Element2 =
case to_index(IndexName) of
Index when Index > 0 ->
OldVal = element(Index, Element),
setelement(Index, Element, OldVal + AddVal); %% {call_ext,3,{extfunc,erlang,setelement,3}},
0 ->
Element
end,
test_d(T, Element2).
to_index(a) -> #r_element.key1;
to_index(b) -> #r_element.key2;
to_index(c) -> #r_element.key3;
to_index(_) -> 0.
test() ->
Element = #r_element{key1 = 10, key2 = 20, key3 = 30},
ListA = [{2, 1}, {3, 2}, {4, 3}, {2, 11}],
A = test_a(ListA, Element),
io:format("A=~w~n",[A]), %% A={r_element,22,22,33}
B = test_b(ListA, Element),
io:format("B=~w~n",[B]), %% B={r_element,22,22,33}
ListB = [{a, 1}, {b, 2}, {d, 3}, {c, 11}],
C = test_c(ListB, Element),
io:format("C=~w~n",[C]), %% C={r_element,11,20,30} ??
D = test_d(ListB, Element),
io:format("D=~w~n",[D]), %% D={r_element,11,22,41}
ok.
Run
c(setelement_test, [debug_info]).
setelement_test:test().
File = "./setelement_test.beam".
rp(beam_lib:chunks(File,[abstract_code])).
rp(beam_disasm:file(File)).
Note: Erlang Runtime System You can query the instructions such as call_ext_last
Fix
test_c([], Element) -> Element;
test_c([{IndexName, AddVal} | T], Element) ->
#r_element{} = Element,
Element2 =
case to_index(IndexName) of
none ->
Element;
Index ->
OldVal = element(Index, Element),
setelement(Index, Element, OldVal + AddVal)
end,
test_c(T, Element2).
to_index(a) -> #r_element.key1;
to_index(b) -> #r_element.key2;
to_index(c) -> #r_element.key3;
to_index(_) -> none.
Others
- To query otp issues, you can directly check the latest fixes in Issues