Site icon FSIBLOG

Solve Erlang Badmatch Error Assigning Lists to Records

Solve Erlang Badmatch Error Assigning Lists to Records

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:

  1. Checking Connection Status: We use the function funcs:hasElem/2 to check if Atom already exists in St#server_st.connectedatoms.
  2. Updating the ConnectedAtoms List: If Atom is not connected (IsConnected == false), we create a new list by appending Atom to St#server_st.connectedatoms.
  3. Creating a New State Record: We then create a new record (e.g., NewSt) instead of attempting to reassign St.
  4. Returning the Updated State: We return the new state NewSt to complete the update without reassigning St.

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:

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.

Exit mobile version