Yes and? EVAL isn’t call/return, it’s a mathematical function from type S-expression to type S-expression modulo some details. At least it was to start, Lisp now has side effects which considerably opens up the domain of easily expressed programs.
Perhaps you’re confused because you’ve never done anything nontrivial in a modern Lisp and the word function is so heavily overloaded?
Here[1] is an example of the Actor model expressed in Common Lisp. It shows a paradigm that is very much not call and return expressed cleanly and directly.
> EVAL isn't call/return, it's a mathematical function
Hmm...a "function" you say. What do you do with a function in a computer system? I mean, for it to actually do something?
Look at it?
Digest it?
Sing it?
Or maybe...call it?
And when that function is done, after you called it what does it do?
Dissolve?
Perambulate?
Or maybe: return?
Of course, a function that you call and that then returns has absolutely nothing to do with the call/return architectural style. Sorry, my bad, what was I thinking?
And no, your example does not invalidate what I wrote, as it doesn't implement it "cleanly and directly", at least not to my standards. Maybe to yours, but not to mine. The problem with Lisp DSLs is that the result always just look like Lisp, and Lisp is eval/apply.
So
(send my-actor message_args)
very much looks like a Lisp function call. It seems to be the function "send" with arguments "my-actor" and "message_args". (Of course the Actor model is close enough that it might not matter). Which is exactly the problem we have in other languages.
At the very least, it would have to be
my-actor async messge_args
For it to qualify as resembling an actual send and not just another function call.
I can also write:
source.connect( target );
And to you that would apparently mean that I have implemented pipes and filters "cleanly and directly" in, say, C++ and Java. And it would be just as wrong.
If you think that the operator in a Lisp form needs to be a function and if it were a function that it needs to return, then that's not the case in Lisp for probably 50+ years.
Lisp is not generally following an eval/apply model and/or call/return model.
(send foo :beep)
This can mean:
* SEND is a function, it's is called with the evaluated args, it may return or not
* SEND is not a function and does something arbitrary
Generally the model is:
(operator ...)
a) Where operator can be a special operator, something built-in, which is not a function.
For example (throw 'foo "hello"), where THROW is a built-in special operator which transfers control.
b) it could be a function, which is more like a procedure. The function could also do transfer control to some other place and never return, for example by calling THROW or by other operators which transfer control
c) it could be a macro. The args don't need to be evaluated. Thus no eval/apply. The macro returns code, which gets executed. Again this could use other primitives, which transfer control.
d) it could be a function itself like ((lambda (x y) ...) 13 14)
What it needs: the first element in a Lisp form needs to be an operator, which is usually a symbol with some meaning: special operator, function, macro.
Scheme then in the mid 70s added that the first element is evaluated and can be a general variable. Thus in Common Lisp:
(let ((actor (create-actor :name 'foo)))
(send-async actor :init))
could be written in Scheme
(let ((actor (create-actor 'foo)))
(actor :init))
given that the actor would be a function object.
> my-actor async messge_args
Writing it as
(send my-actor :async message-args)
Is basically just a syntactic transformation. The semantics could be the same.
If we want write
(my-actor async message-args)
then one would typically
a) switch to a model like in Scheme, where the actor would be a function object
or
b) write a translator for a new language to ordinary Lisp
Perhaps you’re confused because you’ve never done anything nontrivial in a modern Lisp and the word function is so heavily overloaded?
Here[1] is an example of the Actor model expressed in Common Lisp. It shows a paradigm that is very much not call and return expressed cleanly and directly.
[1] https://github.com/naveensundarg/Common-Lisp-Actors