swarm-support
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: List: forEach: arg1;


From: Roger M. Burkhart
Subject: Re: List: forEach: arg1;
Date: Wed, 5 Mar 1997 08:23:04 -0600

Kevin Crowston writes in response to Ludo Pagie:

> "Ludo Pagie" <address@hidden> wrote:
> 
> >-addConcentration: (double) c;
> 
> >[metabList forEach: M(addConcentration:) : myarg];
> >with:
> >
> >>reaction.m: In function `_i_Reaction__react_':
> >>reaction.m:38: incompatible type for argument 4 of indirect function call

The Collection forEach: messages only support argument types compatible
with an id type.  Other types such as int can be passed if they are
cast to an id type.  float and double types cannot be assumed to be
compatible, and so a forEach: message (or a perform: or createActionTo:
message) cannot be used to pass a double argument.  As Kevin notes, you
can pass a pointer to double, but that requires extra work on your part.

The assumptions about argument types are described under the defobj library
"Interface Reference" under "global portability assumptions."  There should
be a link to these assumptions from the forEach: message description that's
contained under the Collection interface reference.  That documentation also
notes:

  The forEach: messages are implemented by a simple loop through all
  members of a collection, using an internal, temporary index. If any
  operation more complex than a simple message send is required, this
  operation should just be coded directly using a loop that traverses its
  own index.

So that's the suggested workaround: just write your own loop that sends your
message that contains a double argument.

> It helps to know that a message send is basically syntactic sugar for a
> function call--the line above is (more or less) turned into the function
> call:
> 
> _i_Reaction__react_(metabList, sel, M(addConcentration), myarg)
> 
> So argument four is myarg.

It's useful to know the internal calling conventions to a method, but you
should avoid referencing the internal, mangled name of a method directly.
That's an internal part of the compiler for the language, and is not part
of the language proper (you do need to know the internal method names to
refer to them under gdb or other debuggers).  The internal method name is
only the compiled location of the method, not all the classes where the
method may also be used by inheritance, so you're really presuming to know
more about the method than you can automatically count on.

The type of a method is defined by the (IMP) typedef (in <objc/objc.h>) as:

  typedef id (*IMP)(id, SEL, ...);

This shows that all arguments after the first are passed in an open-ended
variable arguments section (, ...) which does handle any type in the internal
message send.  

In Swarm, we provide the following method on a class object to obtain a
method pointer that may be used on instances of the class:

  + (IMP) getMethodFor: (SEL)aSel;

Getting method pointers and calling them yourself can be done, but the need
doesn't typically arise in ordinary code.  Once you have the (IMP) method
pointer, Swarm doesn't differ from any other use of gcc Objective C in the
way this is done.

> The incompatible type comes because the forEach:: expects to get id's as
> arguments, and you're passing a double.  I had similar problems in my
> simulation.  What I ended up doing was: (1) switching to float's, since
> they're the same size as id's, at least on a Sun--you might want to verify
> this on whatever you're using. (2) passing the float as an id--this was a
> bit ugly, since it turns out you can't simply cast a float to a pointer.

Our global portability assumptions don't state anything about the size of a
float relative to an id, so you're on your own there.

> What I ended up doing was taking a pointer to my float, casting it to a
> pointer to an id, and deferencing the pointer... ugly at best.  If I
> remember correctly, it looked like:
> 
>            (*((id*)(&f)))
> 
> There's probably a more elegant way, but I think this worked.

This is a reasonable solution if you need to put a message containing
floats or doubles on a Swarm schedule, though it does require changing
the message to avoid the floating type and take a pointer instead.  For
the simple List forEach: case, I'd recommend just coding the for each loop
yourself (see the forEach: code in collections/Collection.m) and
hardcoding the message in the loop that uses the double.

For a scheduled action, if you don't have a choice about changing the message
that needs a a double, you could write a wrapper function that takes
a pointer to float or double like you above and then turns around and
calls the message with the dereferenced double value.  Then you'd schedule
a createActionCall: action that calls the function with a double pointer.

The short answer is that use of floating types in generic messages is not
clean, and can't be assumed compatible with the Objective C id type.  So
your switching to pointers is as good as it gets, under the circumstances.
For perform: and (and forEach:, which follows the same general pattern),
we just live with the limitations.  For scheduled actions, I'd still like
to get a better solution, based on looking at the argument types of the
message, but for now they have the same restrictions as all the rest.

-Roger


reply via email to

[Prev in Thread] Current Thread [Next in Thread]