Thankfully they didn't give it Java like syntax! The syntax is currently a bit more verbose and explicit on dealing with local/micro state which I now like, but without using 100 lines of boilerplate getter/setters. Using pipes gets one enough "OO" syntax feel.
While GenServer's store state they are, in my mind, more akin to microservices than Java/C++ Objects. They're like microservices, but without needing a separate service bus, global naming system (pg2), etc. Now I do wish Dialyzer/Dialyxer also had better support for checking GenServer handler's and messages, especially intra-process. You have a point the syntax their could be spruced up some perhaps. The process / GenServer paradigm kind of remind me of Smalltalk in a way, where you're passing messages that object may or may not want to respond to. That's not really possible with C++/Java objects.