Cannot coerce a BlockCallback to ExternalCallback*

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Cannot coerce a BlockCallback to ExternalCallback*

Chris Uppal-3
I think the following shows a problem in Dolphin, but I doubt if there's any
way to fix it, so this post is more of a warning for the records than a bug
report.

I've been attempting to interface to an external library which makes extensive
use of callbacks, and been having a Great Deal Of Difficulty (tm).  The problem
was that whenever I attempted to use one of the exported functions which took a
callback as parameter, the call would fail with:

    Unhandled exception - an InvalidExternalCall('Invalid arg 3:
    Cannot coerce a BlockCallback to ExternalCallback*')

Which seemed odd enough in itself.  But what made it really puzzling was that
after a while it would start working, and thereafter would work beautifully
(modulo the bugs in the external library).

I've just worked out what the problem is.  My ExternalLibrary's methods are of
the form:

    enumerateSuggestions: aHunspell word: aString callback: anExternalCallback
         <stdcall: sdword enumerateSuggestions void* char* ExternalCallback*>
         ^ self invalidCall.

That will only work if #asParameter has /already/ been sent to the
ExternalCallback in question, since it's only then that it (re-)generates its
#thunk.  If that hasn't been sent then the VM reports (correctly) that the call
failed, and #invalidCall reports (misleadingly) that it was a coercion failure.

Since I was playing with this stuff in a workspace, I had one ExternalCallback
instance (actually a BlockCallback) which I kept re-using.  It wasn't until I
happened to send #asParameter to that BlockCallback that it started to work.
And from then on it continued, most bafflingly, to work...

Applies to D5 and D6.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Cannot coerce a BlockCallback to ExternalCallback*

Blair McGlashan-4
"Chris Uppal" <[hidden email]> wrote in message
news:4440e67f$0$662$[hidden email]...

>I think the following shows a problem in Dolphin, but I doubt if there's
>any
> way to fix it, so this post is more of a warning for the records than a
> bug
> report.
> ...
> I've just worked out what the problem is.  My ExternalLibrary's methods
> are of
> the form:
>
>    enumerateSuggestions: aHunspell word: aString callback:
> anExternalCallback
>         <stdcall: sdword enumerateSuggestions void* char*
> ExternalCallback*>
>         ^ self invalidCall.
>
> That will only work if #asParameter has /already/ been sent to the
> ExternalCallback in question, since it's only then that it (re-)generates
> its
> #thunk.  If that hasn't been sent then the VM reports (correctly) that the
> call
> failed, and #invalidCall reports (misleadingly) that it was a coercion
> failure.
>

This is "by design". It was never intended that ExternalCallbacks should be
directly passable as interop parameters, nor that they could be used as the
parameter type either. If you look in the base image you'll find callbacks
are always declared as lpvoid. It just so happens that because
ExternalCallback has the same initial shape as an ExternalStructure (first
inst var is a byte object), that it is possible to get away with it if the
callback object has been initialised to contain the thunk - i.e. by sending
#asParameter.

I agree the error reporting could be better, and probably the compiler
should not permit ExternalCallback as a parameter type.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Cannot coerce a BlockCallback to ExternalCallback*

Chris Uppal-3
Blair,

> This is "by design". It was never intended that ExternalCallbacks should
> be directly passable as interop parameters, nor that they could be used
> as the parameter type either.

Ok, that makes sense, thanks.


> If you look in the base image you'll find
> callbacks are always declared as lpvoid.

I did look, and would have switched to that way of doing things if I couldn't
make it work the way I preferred.   I don't like using void*-s unless I have
to -- there's too much chance of error with external interfacing so I like
(just for once ;-) the more static approach to typing.  The existing code seems
to use void* more than is necessary, so I didn't realise that in this instance
it /was/ necessary.

Perhaps it would be worth "adding" ;-) a note to that effect to the
ExternalCallback's class comment ?  And perhaps too to the relevant section of
the education centre ?

    -- chris