What should I do cast/2 instead of just sending it a plain message?

Usually, you cast from the client side of your GenServer, so it is also inter-process. A good GenSenver encapsulate its operations so from outside the module it feels like a normal function call.

So instead of:

def doit() do
    GenServer.cast(__MODULE__, :doit)
end
...
def handle_cast(:doit, state) do
    {:noreply, do_something(state)}
end

I can:

def doit() do
    send(__MODULE__, :doit)
end
...
def handle_info(:doit, state) do
    {:noreply, do_something(state)}
end

Same thing?