[Openmcl-devel] delegate problems

Gary Byers gb at clozure.com
Thu Dec 18 21:47:08 UTC 2008


(objc::defmethod (#/speechSyntesizer:willSpeakWord:ofText: :void)
                      ((self some-class)
                       sender
                       (word #>NSRange)
                       (text (:* (:struct #>NSString))))
   ; (do-something-with-args)
   nil)

is one way to define the method, though the description of the last
parameter is a little verbose and doesn't really express the fact that
that parameter is an (NS) object of type NSString.  Before getting
into that, note that the "word" parameter is described in the ObjC
prototype and in the code above as being an #>NSRange, not a pointer
to an NSRange.  From the point of view of how the method would use
the argument, there's no real difference; at a lower level, there
may be a big difference (in how the structure is passed and in whether
it's shared between the caller and callee.)

Back to the last parameter:  it happens to be the case that #>NSString
is defined as a type of structure and it happens to be the case that
the first field in that structure type is called "isa" ("is a ...")
and is statically typed as a pointer to an ObjC class.  In the way
the ObjC extends C's type system, a structure that has a first field
that satisfies those constaints (is called "isa" and is typed as
"pointer to ObjC class" is an ObjC object, and  a builtin type that
describes a pointer to an ObjC object is the type "id".  If you squint,
you can read the ObjC code that says

    (NSString *)text

as declaring text to be "an ID that happens to be an NSString"; it'd
have been correct (in at least some sense) for the prototype to
have said

    (id)text

but the former declaration is saying "an id, that'll be dynamically
typed as NSString or some subclass of NSString"; the more specific
declaration helps the ObjC compiler to do some compile-time typechecking
and helps the reader of the code know just what type of ObjC object
the parameter will be.  The fact that NSString is - at some level and
for historical reasons - a particular kind of structure with certain
fields isn't as interesting as the fact that an NSString is an object
that might have slots and that knows how to respond to certain methods/
messages.  (The less we know about NSString as a structure, the better.)

So, it'd be correct and probably more meaningful to define the method
in lisp as:

(objc::defmethod (#/speechSyntesizer:willSpeakWord:ofText: :void)
                      ((self some-class)
                       sender
                       (word #>NSRange)
                       (text :id))
   ; (do-something-with-args)
   nil)

and, since :id is the default argument type, "(text :id)" can be written
as just "text".  That tells us that "text" is an object, which is probably
a lot more meaningful than saying that it's a pointer to some sort of
structure.  What we'd ideally like (and don't have) is some syntax that
says "not only is it an object, but it's an NSString"), since that would
be more meaningful to the human reader of the code, closer to the syntax
that ObjC uses, and might help to enforce compile-time and/or run-time
typechecking.

Until that syntax exists, just using the (implicit) :id type - and
translating ObjC declarations of the form "(NSSomeClass *)" to :id -
is the right thing.


On Thu, 18 Dec 2008, Alexander Repenning wrote:

> The code below using the mac speech synthesizer works to the point where the 
> speech is produced and the delegate methods are run. Usually this would be 
> the hard part. Instead I have problems with getting the right values from 
> these "callbacks"
>
> Calling startSpeaking will call the speechSynthesizer:willSpeakWord:ofString 
> callback and I get values such as these:
>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Null 
> Foreign Pointer>, text=#<A Foreign Pointer #x4>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Foreign 
> Pointer #x5>, text=#<A Foreign Pointer #x2>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Foreign 
> Pointer #x8>, text=#<A Foreign Pointer #x3>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Foreign 
> Pointer #xC>, text=#<A Foreign Pointer #x4>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Foreign 
> Pointer #x11>, text=#<A Foreign Pointer #x4>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Foreign 
> Pointer #x16>, text=#<A Foreign Pointer #x5>
> sender=#<SYNTHESIZER <Synthesizer: 0x2901490> (#x2901490)> range=#<A Foreign 
> Pointer #x1C>, text=#<A Foreign Pointer #x9>
>
> So far so good.
>
> The callback method is defined as
>
>> speechSynthesizer:willSpeakWord:ofString:
>> Sent just before a synthesized word is spoken through the sound output 
>> device.
>> 
>> - (void)speechSynthesizer:(NSSpeechSynthesizer *)sender 
>> willSpeakWord:(NSRange)wordToSpeak ofString:(NSString *)text
>> 
>
> Redefining the parameter list accordingly: ((Self synthesizer) Sender 
> (wordToSpeak (* (:struct :<NSR>ange))) (text (* :<NSS>tring)))
>
> results in Error: Unknown foreign type: :<NSS>TRING
>
> I tried some permutations of :struct * ns:ns-string without success
>
> Second problem is to try to access the struct values using (pref wordToSpeak 
> :<NSR>ange.length) claiming that the <NSR>ange struct has no field called 
> length and further claiming that <NSR>ange has only a field called nil.
>
> Error: Record type <NSR>ANGE has no field named :LOCATION.
>>        Valid field names are:
>>        NIL
>
> What am I doing wrong?
>
> all the best,  Alex
>
>
> ____________
> (in-package :ccl)
>
>
> (defclass SYNTHESIZER (ns:NS-Speech-Synthesizer)
> ()
> (:metaclass ns:+ns-object)
> (:documentation "Speech Synthesizer"))
>
>
> (defmethod INITIALIZE-INSTANCE :after ((Self synthesizer) &rest Args)
> (declare (ignore Args))
> (#/setDelegate: Self Self))
>
> (#/availableVoices synthesizer)
> (#/defaultVoice synthesizer)
>
>
> (defparameter *Synth1* (make-instance 'synthesizer))
>
>
> (#/startSpeakingString: *Synth1* "What is the deal with these callbacks?")
>
> (objc:defmethod (#/speechSynthesizer:willSpeakWord:ofString: :void) ((Self 
> synthesizer) Sender wordToSpeak text)
> (format t "~%sender=~A range=~A, text=~A" Sender wordToSpeak text))
>
>
> ___________
>
> Prof. Alexander Repenning
>
> University of Colorado
> Computer Science Department
> Boulder, CO 80309-430
>
> vCard: http://www.cs.colorado.edu/~ralex/AlexanderRepenning.vcf
>
>



More information about the Openmcl-devel mailing list