|
|
|
|
|
by pmontra
620 days ago
|
|
This is Elixir syntax, not Gleam: Instead of defmodule Robot do
def handle_call(:get_state, _from, state) do
something()
end
def get_state() do
GenServer.call(__MODULE__, :get_state)
end
end
robot = Robot.start_link()
robot.get_state()
just let me write (note the new flavor of def) defstatefulmodule Robot do
def get_state() do
something()
end
end
robot = Robot.new()
robot.get_state()
Possibly add a defsync / defasync flavor of function definition to declare when the caller has to wait for the result of the function.The idea is that I don't have to do the job of the compiler. It should add the boilerplate during the compilation to BEAM bytecode. I know that there are a number of other possible cases that the handle_* functions can accommodate and this code does not, but this object-oriented-style state management is the purpose of almost all the occurrences of GenServers in the code bases I saw. Unfortunately it's littered by handle_* boilerplate that hides the purpose of the code and as all code, adds bugs by itself. So: add handle_* to BEAM languages for maximum control but also add a dumbed down version that's all we need almost anytime. |
|
If you really don't like the get_state above, I think it'd make more sense to just ditch it, and use GenServer.call(robot, :get_state) in places where you'd call robot.get_state(). Those three lines of definition don't seem to be doing you much good, and calling GenServer directly isn't too hard; I probably wouldn't write the underlying make_ref / monitor / send / receive / demonitor myself in the general case, but it can be useful sometimes.
In my experience with distributed Erlang, we'd have the server in one file, and the client in another; the exports for the client were the public api, and the handle_calls where the implementation. We'd often have a smidge of logic in the client, to pick the right pg to send messages to or whatever, so it useful to have that instead of just a gen_server:call in the calling code.