[Openmcl-devel] New snapshots available
gb at clozure.com
Fri Feb 16 11:43:11 UTC 2007
With just Foundation and AppKit declarations in effect, the "size"
message has 3 declared, each of which returns an :<NSS>ize.
Adding WebKit declarations introduces 6 new methods, with 3 different
return types (:ID, (:SIGNED 32), and (:UNSIGNED 32)).
So, it's neither true that "sending a size message returns a structure"
or "sending a size messsage doesn't return a structure", and there's
nothing that prevents someone introducing another "size" message
that returns some other structure type besides :<NSS>ize.
Unlesss we wanted to insist on type declarations to disambiguate
(and it'd be unfortunate if you had use them in some cases and not
others and very unfortunate if you always had to use them), I don't
really see how we can tell whether a structure's being returned
by an arbitrary SEND or what type if structure's being returned if so.
(Whether this is a problem for much of anything besides "size" is
unclear; it's apparently rare for messages to have some methods
return structures and others not to, but there certainly could be
In the very short term, it's possible to work around this by using
something lower-level, e.g.:
(rlet ((frame-size :<NSS>ize))
(ccl::objc-message-send-stret frame-size string "size" :<NSS>ize)
and the fact that this kind of ambiguity exists should probably be
noted (messages should be marked as ":returns-structure T|NIL|:MAYBE"
rather than just T|NIL, and if you really want to say
(slet ((frame-size (send (the ns:ns-attributed-string ...)))))
it should probably figure out what you mean.)
This does seem like further evidence that things like SLET and
structure return should be buried and that SEND should be phased out
in favor of something generic-function-like.
Suppose that we had that something else (and had a
least-ugly-alternative winner for the naming convention issues).
There are a few obvious lispier alternatives to SLET and exposing
(a) by having their components returned as multiple values:
(multiple-value-bind (frame-width frame-height)
(ns:size (make-instance 'ns:ns-attributed-string :with-string "testing")))
One advantage of this convention is that one could use things like
NTH-VALUE if you're only interested in (for instance) the height
of a string, and passing multiple-values around is (fairly cheap.
A disadvantage is that it's not clear if this approach (viewing
a structure as its individual components) should be extended to
cases where the "value(s)" of that structure is needed:
(ns:do-something-with-size! foo frame-width frame-height)
(ns:init-with-frame! view x y width height)
And, in the case where a message (generic function) has some methods
which involve structure arguments and some which don't, it would lead
to a case where the "generic function" took different numbers of required
arguments according to the class of the specialized argument/receiver,
as well as the case where something like NS:SIZE returned different numbers
of values according to the class of the receiver. Both of those
situations seem undesirable - to me, not quite undesirable enough
to kill the idea, but certainly undesirable.
(b) As Lisp objects (DEFSTRUCTs, something lower-level, CLOS
instances.) This is arguably even "lispier", but has some runtime
costs (memory-allocation and GC) that are hard to avoid. I think
that Randall had some code for coercing between foreign structures
and lisp objects working, and there are probably ways of avoiding
some incidental consing in some cases.
This would lead to:
(let* ((frame-size (ns:size (make-instance 'ns:ns-attributed-string ...))))
(format t "~&Size of string is [~S ~S]"
(let* ((frame (ns:make-rect x y width height)))
(ns:init-with-frame& view frame))
Depending on exactly what an NS:RECT lisp object looked like, it might
be possible to productively stick a (DECLARE (DYNAMIC-EXTENT FRAME))
It might be that the official/high-level way of dealing with foreign
structures is .. to simply not deal with them and deal with the
coresponding lisp objects instead; for occasions when it's just not
practical to do this (e.g., a mouse-tracking loop not wanting to
cons millions of NS:POINTs per second), it'd still be possible to
drop down to SEND/OBJC-MESSAGE-SEND/FF-CALL ...
On Fri, 16 Feb 2007, Phil wrote:
> On Feb 16, 2007, at 1:16 AM, Gary Byers wrote:
>> On Fri, 16 Feb 2007, Phil wrote:
>>> On Feb 15, 2007, at 9:02 PM, Gary Byers wrote:
>>>> Hmm. Could you give me an example of something that fails once
>>>> ambiguity is introduced ?
>>> (ccl::slet ((frame-size (ccl::send (CCL::MAKE-OBJC-INSTANCE
>>> "testing") "size"))))
>>> results in:
>>> NonSTRET SEND in (CCL::SEND (CCL::MAKE-OBJC-INSTANCE
>>> [Condition of type SIMPLE-ERROR]
>> What does
>> ? (ccl::get-objc-message-info "size")
>> return ?
>> (Well, it should return a structure. What do that structure's fields
>> look like ?)
> #S(CCL::OBJC-MESSAGE-INFO :MESSAGE-NAME "size"
> :METHODS (#<OBJC-METHOD-INFO -[NSImageRep size]
> #<OBJC-METHOD-INFO -[NSImage size]
> #<OBJC-METHOD-INFO -[NSAttributedString
> size] #x96DEF96>
> -[DOMCSSStyleDeclaration size] #x96DF07E>
> #<OBJC-METHOD-INFO -[DOMHTMLSelectElement
> size] #x96DF19E>
> #<OBJC-METHOD-INFO -[DOMHTMLInputElement
> size] #x96DF236>
> -[DOMHTMLBaseFontElement size] #x96DF346>
> #<OBJC-METHOD-INFO -[DOMHTMLFontElement
> size] #x96DF466>
> #<OBJC-METHOD-INFO -[DOMHTMLHRElement
> size] #x96DF576>)
> :AMBIGUOUS-METHODS ((#<OBJC-METHOD-INFO
> -[DOMHTMLSelectElement size] #x96DF19E>)
> -[NSAttributedString size] #x96DEF96>
> #<OBJC-METHOD-INFO -[NSImage
> size] #x96DEEDE>
> #<OBJC-METHOD-INFO -[NSImageRep
> size] #x96DEE16>)
> -[DOMHTMLHRElement size] #x96DF576>
> -[DOMHTMLFontElement size] #x96DF466>
> -[DOMHTMLBaseFontElement size] #x96DF346>
> -[DOMHTMLInputElement size] #x96DF236>
> -[DOMCSSStyleDeclaration size] #x96DF07E>))
> :REQ-ARGS 0 :FLAGS (:AMBIGUOUS T))
More information about the Openmcl-devel