I’m trying to assign the ConnectedAtoms
list to the connectedatoms
field inside a newly created server_st
record, but I keep running into a badmatch
error. Here’s the setup: I’m using a loop/2
function to check if an Atom
is already connected by calling funcs:hasElem
on St#server_st.connectedatoms
. If it’s not connected, I want to update connectedatoms
by appending the new Atom
to it. However, when I attempt to create the new St
with #server_st{servername=St#server_st.servername,connectedatoms=ConnectedAtoms}
, Erlang throws a badmatch
error. I suspect the issue lies in how I’m handling the assignment, but I can’t pinpoint what’s going wrong here.
Error Code:
code-module(server).
-export([loop/2, initial_state/1]).
-include_lib("./defs.hrl").
loop(St, {tryConnect, Atom}) ->
IsConnected = funcs:hasElem(St#server_st.connectedatoms, Atom),
if
IsConnected == true ->
{'EXIT', user_already_connected};
IsConnected == false ->
ConnectedAtoms = St#server_st.connectedatoms ++ [Atom],
St = #server_st{servername = St#server_st.servername, connectedatoms = ConnectedAtoms},
{"Connected!", St}
end;
loop(St, _Msg) ->
io:format("Server got message.~n"),
{ok, St}.
initial_state(_Server) ->
#server_st{servername = _Server, connectedatoms = []}.
The badmatch
error occurs because Erlang variables are immutable, meaning you cannot reassign St
after it has been defined. To handle this correctly, we need to create a new variable for the updated state rather than trying to reassign St
.
Solution:
- Checking Connection Status: We use the function
funcs:hasElem/2
to check ifAtom
already exists inSt#server_st.connectedatoms
. - Updating the ConnectedAtoms List: If
Atom
is not connected (IsConnected == false
), we create a new list by appendingAtom
toSt#server_st.connectedatoms
. - Creating a New State Record: We then create a new record (e.g.,
NewSt
) instead of attempting to reassignSt
. - Returning the Updated State: We return the new state
NewSt
to complete the update without reassigningSt
.
Correct code:
code-module(server).
-export([loop/2, initial_state/1]).
-include_lib("./defs.hrl").
loop(St, {tryConnect, Atom}) ->
IsConnected = funcs:hasElem(St#server_st.connectedatoms, Atom),
if
IsConnected == true ->
{'EXIT', user_already_connected};
IsConnected == false ->
ConnectedAtoms = St#server_st.connectedatoms ++ [Atom],
NewSt = #server_st{servername = St#server_st.servername, connectedatoms = ConnectedAtoms},
{"Connected!", NewSt}
end;
loop(St, _Msg) ->
io:format("Server got message.~n"),
{ok, St}.
initial_state(_Server) ->
#server_st{servername = _Server, connectedatoms = []}.
Explanation of Changes:
- New Variable (
NewSt
): Instead of reassigningSt
, we createNewSt
to hold the updated state after addingAtom
toconnectedatoms
. - Returning
NewSt
: In theif
clause whereIsConnected == false
, we return{"Connected!", NewSt}
to represent the updated state.
This code will now run without the badmatch
error because St
is not being reassigned. Instead, a new state (NewSt
) is created and returned, keeping with Erlang’s immutability requirements.
Final Thought:
The key to resolving the badmatch
error in Erlang lies in understanding its immutability constraints. By avoiding variable reassignment and creating a new state record, we respect Erlang’s functional nature and maintain cleaner, error-free code. This approach not only fixes the error but also reinforces best practices in handling state updates in Erlang, especially within record-based structures. Embracing these principles leads to more robust, predictable, and maintainable code in the long run.