Interesting thing about term share

in shell or function
play with erlang shell

f(), A = {a, 1}, B = [A],
true = erts_debug:same(A, hd(B)),
false = erts_debug:same({a, 1}, {a, 1}).

found

  1. share when using same variable

in module file

-module(test).
-compile([export_all,nowarn_export_all]).
t1() -> {a,1}.
t2() -> {a,1}.
t3() -> [{a,1}, {a,1}].
t4() -> [{a,1}, {a,1}].
t() -> 
    [
        %% same return
        {t1_t2, erts_debug:same(test:t1(),test:t2())},
        {t3_t4, erts_debug:same(test:t3(),test:t4())},
        %% deep struct
        {t1_t3, erts_debug:same(test:t1(),hd(test:t3()))},
        {t3_t3, erts_debug:same(hd(test:t3()), lists:nth(2, test:t3()))}
    ].

play with erlang shell

c(test),test:t().

result

[{t1_t2,true},{t3_t4,true},{t1_t3,false},{t3_t3,false}]

found

  1. share between function if function retuen same literal(t1_t2 and t3_t4)
  2. will not share in deep struct(t1_t3, t3_t3)

in persistent_term

-module(test).
-compile([export_all,nowarn_export_all]).
p() -> p({a,1}).
p(A) ->
    persistent_term:erase(p1),
    persistent_term:erase(p2),
    persistent_term:erase(p3),
    persistent_term:erase(p4),
    persistent_term:erase(p5),
    persistent_term:put(p1, {a, 1}),
    persistent_term:put(p2, [{a, 1}, {a, 1}]),
    persistent_term:put(p3, [A, A]),
    persistent_term:put(p4, [A, A]),
    persistent_term:put(p4, [{a, 1}, {a, 1}]),
    persistent_term:put(p5, [{a, 1}, {a, 1}]),
    persistent_term:put(p5, [A, A]),
    DeepSame = fun(Key) -> erts_debug:same(
        lists:nth(1,persistent_term:get(Key)),
        lists:nth(2,persistent_term:get(Key))
        ) end,
    [
        %% same variable
        {p1, erts_debug:same(persistent_term:get(p1),persistent_term:get(p1))},
        %% deep struct
        {p2, DeepSame(p2), erts_debug:size(persistent_term:get(p2))},
        {p3, DeepSame(p3), erts_debug:size(persistent_term:get(p3))},
        %% keep old share state
        {p4, DeepSame(p4), erts_debug:size(persistent_term:get(p4))},
        {p5, DeepSame(p5), erts_debug:size(persistent_term:get(p5))}
    ].

play with erlang shell

c(test),{test:p(),test:p({a,1})}.

result

{[{p1,true},
  {p2,false,10},
  {p3,false,10},
  {p4,false,10},
  {p5,false,10}],
 [{p1,true},
  {p2,false,10},
  {p3,true,7},
  {p4,true,7},
  {p5,false,10}]}

found

  1. share when using same variable(p1 and p3), but test:p/0 will not share, maybe compile p({a,1}) as literal?
  2. keep old share state(p4, p5), when put the value equal to the value previously stored