[Openmcl-devel] To send or not to send

Gary Byers gb at clozure.com
Fri May 29 16:56:04 PDT 2009

SEND is/was a macro; it macroexpanded into something like:

(#_objc_msgSend <receiver> (@selector "someObjcMessage:withArg:andOtherArg:")
    :id arg0 :int arg1 :id)

or in some cases:

(#_objc_msgSendStret <pointer-to-returned-structure> <receiver ...>)

depending on what information about the ObjC message's argument and return
types was available at macroexpand time.  The second case (assuming that
I'm spelling the foreign function names correctly) was used when the
ObjC method returned a structure (in all cases on PPC32 and in some
cases on other architectures.)  Cases that involved structure return
in SEND (regardless of what runtime function actually implemented structure
return) had to be treated differently and generally had to be embedded in
an SLET form (or something equally awkward.)

For the vast majority of ObjC messages defined in Cocoa (AppKit and Foundation),
all methods defined on the message have the same foreign type signature (accept
the same types of foreign arguments and return the same type of value.)  There
are a few exceptions to this (where the same message name is used for different
methods in disjoint classes and those messages had different type signatures),
and there's a section in the manual that describes how to provide hints which
help resolve ambiguity.  I'm not sure how well users dealt with this - sometimes
type declarations were required in order to get a SEND macro call to compile,
sometimes they weren't, and loading additional frameworks changed the rules.

Loading additional frameworks could exposed different kinds of ambiguity.
In AppKit and Foundation, there are 4 declared #/size methods, each of which
returns an NSSize structure (and therefore had to be used inside an SLET or
otherwise satisfy SEND's contstraints on structure-returning message sends.)
Loading the WebKit framework defines a #/size method that returns a scalar
value (I don't remember whether it's an integer or a float), and I think
that SEND just threw up its hands and either refused to macroexpand 
(SEND x 'size) anymore or completely lost the ability to do so correctly.
Users ran into this, and the precise details of the ways in which it failed
and the bizarre workarounds that were necessary to avoid failure are presumably
still in the openmcl-devel archives and not too hard to find.

It might have been possible to fix SEND to better deal with this (rare) kind
of ambiguity, but whatever the fix was would have likely required the user
to provide even more declarative information and to be even more sensitive
to the FFI-level details of how structure-returning calls differ from
scalar-returning calls.

There were other arguments for wanting to deprecate SEND in favor of
#/.  #/ returns a lisp symbol (although bizarrely named) that likely
names a lisp function (although a somewhat unusual lisp function), and
an invocation of an ObjC method via (#/messagename foo ..) is just a
lisp function call (so the compiler can warn if the function is undefined
or if the number of arguments is inappropriate).  Meta-. doesn't do
anything with methods named via #/, but you don't have to stretch
too far to see the possibility that it could (and one of the things
that could be done is to visit the .h file that defines the method
when appropriate.)  Perhaps most importantly, treating ObjC messages
as lisp functions allowed those functions to deal with foreign type
ambiguity and hide the details of that from the user, and to deal
with structure-returning methods by treating structures as values
that're returned just like other values are.

Not to keep bashing SEND - which was contributed by a user named
Randall Beer and which was a huge step up from the much more primitive
things that'd existed before - but some people complained that the
infix-y/mixed syntax felt too much like ObjC and too little like lisp.
Different people will view that kind of thing differently, but one
thing that most lisp programmers will likely agree on is that syntax
is easy to change and often uninteresting.  There are lots of problems
(as enumerated above) with SEND macroepanding into an ff-call into the
ObjC runtime, and many of those problems have to do with issues of
foreign type ambiguity that can't be resolved at macroexpand time.  If
SEND instead macroexpanded into a function call to the function named
by #/, those problems would go away.  (E.g., if

(send foo 'size)

macroexpanded into the equivalent of

(#/size foo) ; let #'#/size figure out whether to return a struct or scalar

then there'd be far fewer reasons to want to deprecate it.)

On Fri, 29 May 2009, Ron Garret wrote:

> This is not a high priority issue for me, but I thought it might be of 
> general interest.
> RME (whom I presume is Ralph Emerson) commented on a recent ticket of mine 
> (#516):
> "I would recommend that you don't use SEND, which is basically obsolete.
> (Yes, the Objective-C bridge chapter in the manual is horribly out-of-
> date.)"
> I was disappointed by this because I kinda sorta like the send syntax better 
> than the straight ObjC syntax.  There are times when:
> (send foo ns::snoz :baz bar :bing boff)
> just feels cleaner than
> (#/snozBazBing: foo bar boff)
> especially when there are a lot of arguments.  Why is send being deprecated?
> rg

More information about the Openmcl-devel mailing list