Discussion:
Rant: syntactical sugar & message passing
(too old to reply)
n***@ind.tansu.com.au
2000-12-14 21:36:52 UTC
Permalink
I wrote:
> If this is correct, it confirms my horrible suspicion that
> something like [Controller warningAlert: text] is just syntactical
> sugar equivalent to Controller.warningAlert(text).
>
> Please, say it ain't so!


Right on cue, Marcel Weiher answered:
>
> It ain't so. It is just syntactical sugar for
>
> objc_msgSend( Controller, @selector(warningAlert:), text);


That is true, but what I was getting at was that the Obj-C
syntax for passing a message really is just calling a function in
an instance of the class.

e.g. if Controller was an instance of a C++ class, then we are really
just calling a method warningAlert of it, with the arg. text:
Controller.warningAlert(text);

The sender and receiver are in the same Kernel Task (thus share the
same memory space), but are separate threads, and have different
environments (e.g. the receiving class was created via loadNibNamed:
and has an autorelease pool), yet there is no passing of any message
between the two environments.



If objc_msgSend was really message passing, wouldn't it:

1) Package the selector and args up into a stream of bytes

2) Pass the target and message to a transport mechanism,
which would check that the receiver is in the current task's
memory space/autorelease pool/whatever, and copy the message
into a shared buffer if it was not

3) Send the message to a listening port running as part of the
instantiated object. If it doesn't respond to that message,
it tries the object's superclass

4) Send the result back, via the message passing mechanism,
as a return value



Now, Dist. Objects will do most of this, but distributed
to me implies different Kernel Tasks, or different processors.
e.g. across a LAN.



I guess I am getting back to where I was a few months ago.
I disliked the Obj-C syntax because it seemed to be just a non-
standard way of calling a function in a class. Yes there are
documentation benefits in the named parameters, but if it is
not really sending a message, why bother with the objc_msgSend()
stuff? Why not just directly call our selectors via function calls?

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Adam Bridge
2000-12-14 22:01:40 UTC
Permalink
> I guess I am getting back to where I was a few months ago.
> I disliked the Obj-C syntax because it seemed to be just a non-
> standard way of calling a function in a class. Yes there are
> documentation benefits in the named parameters, but if it is
> not really sending a message, why bother with the objc_msgSend()
> stuff? Why not just directly call our selectors via function calls?

Obj-C mimics the syntax of Smalltalk which is about as object-oriented as a
language gets since EVERYTHING in Smalltalk is an object.

The operation of Objective-C dispatches in much the same way as Smalltalk
too: it's dynamic. Smalltalk has the (dis)advantage (choose your point of
view) that it's type-less. I like it, others don't.

Objective-C, however, IS a fully object-oriented dynamic language. It's the
real thing. Not quite compiled Smalltalk but as close as many folks might
care to get.
Andreas Monitzer
2000-12-14 22:05:27 UTC
Permalink
On Friday, December 15, 2000, at 12:35 AM, ***@ind.tansu.com.au wrote:

> I wrote:
> If objc_msgSend was really message passing, wouldn't it:
>
> 1) Package the selector and args up into a stream of bytes
>
> 2) Pass the target and message to a transport mechanism,
> which would check that the receiver is in the current task's
> memory space/autorelease pool/whatever, and copy the message
> into a shared buffer if it was not
>
> 3) Send the message to a listening port running as part of the
> instantiated object. If it doesn't respond to that message,
> it tries the object's superclass
>
> 4) Send the result back, via the message passing mechanism,
> as a return value

If EVERY message would do all of this, I don't think I'd be writing this in Apple Mail. I'd be waiting for an hour for the message window to pop up.
Maybe someday with terabit networks and petahertz computers this will be possible, but don't forget that NextStep was written for a 25MHz 68040 CPU (afaik).

> I guess I am getting back to where I was a few months ago.
> I disliked the Obj-C syntax because it seemed to be just a non-
> standard way of calling a function in a class. Yes there are
> documentation benefits in the named parameters, but if it is
> not really sending a message, why bother with the objc_msgSend()
> stuff? Why not just directly call our selectors via function calls?

Maybe you think too much about it. Why don't just use it?

Why should Controller.warningAlert(text) be more direct than [Controller warningAlert:text]? Is it as direct as Controller->warningAlert(text) or more like Controller.warningAlert().setText(text)?

You just need objc_msgSend if you want to send an objc-message from C (a thing that isn't possible with C++).

The basic idea behind this is that if you can write selectors as strings (like '@selector("warningAlert")') and catch unhandled messages by a default method, you could dynamically create new methods, parse text without a switch, use objects you never saw yourself (like Java's reflection), exchange not binary identical objects without altering the other binary code, do not require strict typing, subclassing and interfaces like in Java.
I know some (most?) Java-programmers don't like this way of programming, but that's Objective C. Use whatever you want.

andy


--
Description forthcoming.
Greg Titus
2000-12-14 22:20:04 UTC
Permalink
> I disliked the Obj-C syntax because it seemed to be just a non-
> standard way of calling a function in a class. Yes there are
> documentation benefits in the named parameters, but if it is
> not really sending a message, why bother with the objc_msgSend()
> stuff? Why not just directly call our selectors via function calls?

How about: Because the destination object of your message COULD
TRANSPARENTLY be in some other environment - another category or object or
thread or task or across a LAN or WAN (using categories or forwarding or
Distributed Objects, or some other mechanism). The reason for dynamic
binding is to add the FLEXIBILITY to do these things.

That fact isn't disproved simply because 99% of the time you don't have to
do those things and the message invocation is treated much like a function
call. You should think of that as an optimization of the common case.

If I have a silly method like this:

- (BOOL)doStuffToObject:aFoo
{
[aFoo doFirstStuff];
[aFoo doMoreStuff];
return [aFoo howDidThatGo];
}

Maybe those 3 method calls are going to be the equivalent of functions.
Most of the time they are, because I'm going to be passed an object in the
same task. But my code could be passed "aFoo" that is a proxy for an object
in another thread, another task, another machine, a composite that
forwards each of the three methods to entirely different objects which may
themselves be distributed in different tasks or machines.... maybe even
more interesting things like an object that doesn't do anything, just
records what calls are made upon it to possibly be replayed later (see the
undo management in AppKit for instance).

Whatever wild stuff may be happening, I could care less. My code is
written the same, compiles to the same "syntactic sugar"... but having the
dynamic dispatch of objc_msgSend() vs. ALWAYS having a straight function
call means whoever is calling my code has that extra flexibility, even if
it is only used 1 out of a 100 times.

THAT is the difference.

However, the message passing only gives you the ABILITY to do these
things, it doesn't magically figure out that you want your -warningAlert:
method to be invoked in a different thread. How could it? When I write
multithreaded programs I often have objects that I want methods invoked
from different threads at the same time - this wouldn't be possible if an
object "belonged" to a thread the way you seem to want it to.

Instead, the default is for an object's methods to be invoked using
whatever thread the caller is executing in. If you want to change this, the
easiest way is to use Distributed Objects. Just because "distributed"
implies between machines doesn't mean that it isn't just as useful between
threads. Check out the "Forming Connections Between Threads" section of the
NSConnection documentation for an explanation and example of how to do
exactly what you are attempting.

Hope this helps,
Greg
John Hörnkvist
2000-12-14 22:38:53 UTC
Permalink
Nigel Pearson wrote:
> The sender and receiver are in the same Kernel Task (thus share the
> same memory space), but are separate threads, and have different
> environments (e.g. the receiving class was created via loadNibNamed:
> and has an autorelease pool), yet there is no passing of any message
> between the two environments.
>

A thread is only a locus of control. Fundamentally, the only resources owned by a thread are register state and program counter. There is some extra information _associated_ with a Cocoa thread, among them the autorelease pool.

How can the object know in what thread it lives? It cannot; a thread does not own memory.
Threads share memory; the very point of multi threading is that you use shared memory to communicate between the threads, which is a very cheap communications channel.

Thus, the normal case is that an object's methods can be simultaneously accessed by multiple threads. If you don't want this behavior, you set up a different communications channel; Distributed Objects is very convenient for it.

In the case you describe, the objects simply don't have different environments, so there cannot be "passing of any message between the two environments". If you want objects to live in different environments you put them in different tasks.

Any method invocation can be packed up as a stream, but this is not done unless it is necessary. (This happens when the messaging system finds that the receiver can't handle the message it tries to send; look at forwardInvocation:.)

Function calls are statically bound; it is completely known at compile time what the semantics of a certain function call are. That is not true of method invocations; the semantics can vary as the program runs.

Some of what differentiates an Objective-C method invocation from a function call is:
Polymorphism.
Not much different from C++ style object.function()
Except:
Matching can be used instead of subtyping.
Protocols are an example of matching.

Non-determinism.
It is not know until invocation time what function is associated with a certain selector for a certain object.
Allows extension and amendment, at any time.

Fault recovery/message forwarding.
It is up to the receiver to decide what to do when it doesn't have a method that matches the selector.
This allows Marcel's HOM (MPWFoundation) and my Concrete Protocols, as well as EOFault (lazy evaluation), Distributed Objects, delegation and much more.

Anonymous invocation.
No need to know anything about the receiver until the time of invocation.

The semantics of an Objective-C message call are vastly different from the semantics of a C function call. Thus, it makes very good sense to have a syntactical difference.

If you give up on matching, non-determinism and anonymous invocation, you have a method semantics like that in SmallEiffel:

object.doSomething(anObject) // The type of object is the set {Number, String}
is
if (object->isa == Number)
doSomething_Number(object,anObject);
else
if (object->isa == String)
doSomething_String(object,anObject);

In Objective-C you can't describe the semantics like this, because the type of object would be unbounded (undecidable) at compile time, so you'd have to enumerate over all classes available at invocation time...

With all that can be going on in an Objective-C method invocation --- posing, swizzling, forwarding, etc--- I'd say that it is lucky the syntax is so different.

Regards,
John Hornkvist


--
ToastedMarshmallow, the perfect Cocoa companion
http://www.toastedmarshmallow.com
n***@ind.tansu.com.au
2000-12-14 23:34:03 UTC
Permalink
I asked:
> Why not just directly call our selectors via function calls?


Greg answered:
...
> {
> [aFoo doFirstStuff];
> [aFoo doMoreStuff];
> return [aFoo howDidThatGo];
> }
>
> Maybe those 3 method calls are going to be the equivalent of functions.
> Most of the time they are, because I'm going to be passed an object in the
> same task. But my code could be passed "aFoo" that is a proxy for an object
> in another. thread another task, another machine,

Hell yes. Though, how is calling a proxy via [aFoo do]
really any different from calling a proxy via aFoo.do() ?
Isn't a proxy just a set of methods/functions that do message
passing to the target object?

(e.g. I could do the same in C using SunOS RPC calls)


I can see that the "dynamic binding" in Obj-C means that
the call is always (*aFoo).do(), instead of what a C++ programmer
would usually code - aFoo.do(), so perhaps that is the concept
that I have to wrap my head around.


Calling the [target selector] syntax "a message" or
"message passing" is the problem for me - conceptually it
doesn't actually seem to pass a message.


...
> However, the message passing only gives you the ABILITY to do these
> things, it doesn't magically figure out that you want your -warningAlert:
> method to be invoked in a different thread. How could it?

The class that contains warningAlert:, when instantiated,
has a message receiver created. objc_msgSend(target, ...) locates
an instantiated receiver that matches target, first in the calling
thread, then in the Task's other threads, then in a meta (DO stuff).
It then sends the message, which is copied to the receiver's memory
space if needed.


> When I write multithreaded programs I often have objects that I
> want methods invoked from different threads at the same time -

True. Synchronicity issues do complicate message passing.
Blocking is why writing multithreaded stuff is hard.

> this wouldn't be possible if an object "belonged" to a thread
> the way you seem to want it to.

In my theoretical message passing system, the Class's
message receiver would do the arbitration (it would FIFO queue
incoming messages, and each class could only be executing the
selector of one message at a time), and there may be a version
of objc_msgSend that has a timeout parameter.


> Instead, the default is for an object's methods to be invoked using
> whatever thread the caller is executing in. If you want to change this, the
> easiest way is to use Distributed Objects. Just because "distributed"
> implies between machines doesn't mean that it isn't just as useful between
> threads. Check out the "Forming Connections Between Threads" section of the
> NSConnection documentation for an explanation and example of how to do
> exactly what you are attempting.

Cool, Thanks, I will look that up.

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Steve Israelson
2000-12-14 23:50:40 UTC
Permalink
> > [aFoo doFirstStuff];
>> [aFoo doMoreStuff];
>> return [aFoo howDidThatGo];
>> }
>>
>> Maybe those 3 method calls are going to be the equivalent of functions.
>> Most of the time they are, because I'm going to be passed an object in the
>> same task. But my code could be passed "aFoo" that is a proxy for an object
>> in another. thread another task, another machine,
>
> Hell yes. Though, how is calling a proxy via [aFoo do]
>really any different from calling a proxy via aFoo.do() ?
>Isn't a proxy just a set of methods/functions that do message
>passing to the target object?

Well, the message passing means that the target for the message, ie
what function to call, is actually calculated at run-time. This is
different from C++, where it is always calculated at compile-time
(even v-tables are made at compile-time). I could write a class that
is completely unrelated to what you expect, but happens to have the
same method name as the message you are passing. This will work and
pass that message to my object in Objective-C but NOT in C++ nor Java
etc. This is because the message is matched with a method to execute
at run-time.

Further more, I could add to classes in a program you wrote, without
your knowledge, and without the source code, and STILL have the
messages go to the correct method.

So, to sum up, calling a function is like jumping to an address
during run-time, but sending a message is like looking at all the
methods and seeing which one can handle the message and then calling
that one.
--

* These comments MAY not be those of Totally Hip Software :) *
Steve Israelson
Totally Hip Software www.totallyhip.com
Steve Dekorte
2000-12-15 00:33:38 UTC
Permalink
Nigel Pearson wrote:
> I guess I am getting back to where I was a few months ago.
> I disliked the Obj-C syntax because it seemed to be just a non-
> standard way of calling a function in a class. Yes there are
> documentation benefits in the named parameters, but if it is
> not really sending a message, why bother with the objc_msgSend()
> stuff? Why not just directly call our selectors via function calls?

Hi Nigel,

This is a common point of confusion - the subtle power of dynamic
OO takes some time to get used to.

Here are a few reasons why:

- The receiver type may not be defined at compile time, so there is no
way of knowing which function to link to.

- The method you're calling may not exist.
(You may want the receive to catch it in it's forward:: method.)

- The method may get overridden by a category loaded at runtime.

I'm sure there are many more. The important thing to understand is that
you gain a lot of flexibility and power through this abstraction without
loosing much speed. For example, dealing with lists of objects of different
types is a non issue in Objective-C, but a major hassle in C++.

I think it's also worth mentioning that most modern VM based languages do this.
(Java, JavaScript, Python, Perl, Ruby, Lua, Tcl, etc.)
So Objective-C isn't odd in this respect.

Steve
Erik M. Buck
2000-12-15 01:32:34 UTC
Permalink
> > It ain't so. It is just syntactical sugar for
> >
> > objc_msgSend( Controller, @selector(warningAlert:), text);
>
>
> That is true, but what I was getting at was that the Obj-C
> syntax for passing a message really is just calling a function in
> an instance of the class.

NO. The key is that all arguments to object_msgSend are variable. The
flexibility of having a variable selector enables so many possibilities.
Variable selector's alone make half of the now famous C++ design patterns
unnecessary in Objective-C.

The construct
someInstance.DoSomething(someArgument);
is less flexible because "DoSomething" is hard coded. This fact alone
necessitates "Interface Definition Language", systems like COM/DCOM,
bmessages, the command pattern, and lots of code not needed in Objective-C.

Furthermore, the fact that Objective-C enables messages to be sent to
anonymous objects (The compiler can not and will not verify that the
receiver will respond to the message) enables distributed messaging,
plug-ins, the responder chain (chain of responsibility pattern without the
command pattern), categories, posing, proxies (another pattern), etc.

The difference that you want to overlook is crucial and powerful.
n***@ind.tansu.com.au
2000-12-15 02:25:01 UTC
Permalink
[long example of message passing by me deleted]

Andreas answered:
>
> If EVERY message would do all of this, I don't think I'd be writing
> this in Apple Mail. I'd be waiting for an hour for the message window
> to pop up.

Maybe, though I am sure that there would be caching of a
lot of stuff. (I assume the Obj-C compiler & runtime cache some
information so that choosing a selector is faster than using a
class-by-class search).



Thread "environment" discussion by me:
> The sender and receiver are in the same Kernel Task (thus share the
> same memory space), but are separate threads, and have different
> environments (e.g. the receiving class was created via loadNibNamed:
> and has an autorelease pool), yet there is no passing of any message
> between the two environments.
>

John H. clarified:
> A thread is only a locus of control. Fundamentally, the only
> resources owned by a thread are register state and program counter.
> There is some extra information _associated_ with a Cocoa thread,
> among them the autorelease pool.
> How can the object know in what thread it lives?

The only other way would be to have one thread per object,
or have an OS-level manager for this stuff.

[As an aside, did anyone do low-level programming under AmigaOS?
I seem to remember that it did "real" message passing, and used
a special memory type for the message buffers (for MMU compat.)]

...
> Thus, the normal case is that an object's methods can be
> simultaneously accessed by multiple threads.

Yes, that is certainly the case for most languages.
In this case, I guess I was hoping that Cocoa and Objective-C
somehow did something different for the UI stuff.


...
> In the case you describe, the objects simply don't have different
> environments

Well, except for the fact that I can draw UI stuff in one,
and not in the other :-)

But I do see what you are saying.

[I wonder if it is just the lack of an autorelease pool that is
causing the draw-from-a-non-NSThread-thread failure, or if there
is some other Cocoa stuff missing. I couldn't tell from the trace]


...
> Any method invocation can be packed up as a stream, but this is
> not done unless it is necessary. (This happens when the messaging
> system finds that the receiver can't handle the message it tries
> to send; look at forwardInvocation:.)

Aah. I am confused again now. So, an objc_msgSend()
_can_ actually send a message? (in contrast to invoking
a function in a proxy which does its own messaging)


...
> Non-determinism.
> It is not know until invocation time what function is associated with a certain selector for a certain object.
> Allows extension and amendment, at any time.

Woa. I didn't realise that was possible.




Thanks for your clarifications, John. Looks like it is time
to re-read the manual, and to try and understand these examples:

...
>This allows Marcel's HOM (MPWFoundation) and my Concrete Protocols,
> as well as EOFault (lazy evaluation), Distributed Objects,
> delegation and much more.

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Bill Bumgarner
2000-12-15 02:45:05 UTC
Permalink
Greg makes an excellent point. And as a very specific example of exactly why that is SO DAMNED COOL have a look at the undo architecture in Cocoa.

Basically, it stores arrays of NSInvocation objects that are configured to push/pop changes to the object model/document.

It is elegant.

It requires almost no effort on the part of the develper [save for what always has to be done for undo/redo-- making sure things can be undone/redone].

It is incredibly flexible.

It could NOT be done in C++ or Java in anywhere near as transparent of a fashion!

b.bum


On Thursday, December 14, 2000, at 08:42 PM, macosx-dev-***@omnigroup.com wrote:

> How about: Because the destination object of your message COULD
> TRANSPARENTLY be in some other environment - another category or object or
> thread or task or across a LAN or WAN (using categories or forwarding or
> Distributed Objects, or some other mechanism). The reason for dynamic
> binding is to add the FLEXIBILITY to do these things.
>
Peter Bierman
2000-12-15 05:10:35 UTC
Permalink
At 3:23 PM +1100 12/15/00, ***@ind.tansu.com.au wrote:

>[I wonder if it is just the lack of an autorelease pool that is
> causing the draw-from-a-non-NSThread-thread failure, or if there
> is some other Cocoa stuff missing. I couldn't tell from the trace]


Chris Kane answered this in a message to the list on 11/20:

>> However, when I try to do any sort of drawing (e.g. updating a button's
>> title) from within the callback, AppKit seems to stop flushing drawing to
>> the screen. All the controls work and everything, but nothing in the
>> window gets updated unless I minimize it and un-minimize it, even
>> including the window controls at the window's upper left corner.
>>
>
>AppKit is more or less thread-safe, but this safety is triggered by the
>spawning of the first NSThread. For performance reasons, thread-safety
>setup (and then perpetual execution in "thread-safe" mode) is delayed
>until the first NSThread is created. After the NSThread is created, you
>can access AppKit from random non-NSThread threads.
>
>The usual technique here is to spin off a thread to do something trivial:
>
>[NSThread detachNewThreadSelector:@selector(self) toTarget:anyObject
>withObject:nil];
>
>where "anyObject" is any object you like. Do this early in your app.
>
>Chris Kane
>Cocoa Frameworks, Apple Inc.


--
"Every time you provide an option, you're asking the user to make a decision.
That means they will have to think about something and decide about it.
It's not necessarily a bad thing, but, in general, you should always try to
minimize the number of decisions that people have to make."
http://joel.editthispage.com/stories/storyReader$51
Peter Bierman
2000-12-18 21:39:32 UTC
Permalink
At 10:24 AM +1100 12/19/00, ***@ind.tansu.com.au wrote:

>2) Since it is a little messy to allocate a pool from the C function
> that pthread_create() calls, it looks like NSThread is the best
> way to do all of this


Why is it messy?

Just:

void my_thread_entry(...)
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];

...existing thread body...

[pool release];
}

-pmb

--
"Every time you provide an option, you're asking the user to make a decision.
That means they will have to think about something and decide about it.
It's not necessarily a bad thing, but, in general, you should always try to
minimize the number of decisions that people have to make."
http://joel.editthispage.com/stories/storyReader$51
Christian Brunschen
2000-12-15 08:27:56 UTC
Permalink
On Thu, 14 Dec 2000, Peter Bierman wrote:

> >The usual technique here is to spin off a thread to do something trivial:
> >
> >[NSThread detachNewThreadSelector:@selector(self) toTarget:anyObject
> >withObject:nil];

I just had a thought - wouldn't it be nice if NSThread had a method that
allowed a nicer syntax for the above, using the same sort of design as in
the undo framework and Marcel's Higher-Order Messaging? So that we could
do something like

[[NSThread detachWithTarget:foo] workWith:anArgument and:anotherArgument];

Hmmm ....

@implementation NSThreadStarter : NSObject {
id target;
}
- initWithTarget:(id)t {
self = [super init];
target = t;
return self;
}
- (void) _runWithInvocation:(NSInvocation *)invocation {
NSAutoreleasePool *pool = [NSAutoreleasePool pool];
[invocation invoke];
[pool release];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:target];
[NSThread detachNewThreadSelector:@selector(_runWithInvocation:)
toTarget:self
withObject:invocation];
}
@end

@implementation NSThread (HigherOrderDetaching)
- (NSThreadStarter *)detachWithTarget:(id)target {
return [[[NSThreadStarter alloc] initWithTarget:target] autorelease];
}
@end

... would something like this work? I don't have a Foundation-running
machine available to test this on at the moment ... and even if it would
work, does it make sense?

> >where "anyObject" is any object you like. Do this early in your app.
> >
> >Chris Kane
> >Cocoa Frameworks, Apple Inc.

// Christian Brunschen
Frederic Stark
2000-12-15 09:15:44 UTC
Permalink
I missed the start of this thread, but it looks like nigel still
have the power to start threads that will not die (tm).

> I guess I am getting back to where I was a few months ago.
> I disliked the Obj-C syntax because it seemed to be just a non-
> standard way of calling a function in a class. Yes there are
> documentation benefits in the named parameters, but if it is
> not really sending a message, why bother with the objc_msgSend()
> stuff? Why not just directly call our selectors via function calls?

You cannot call a selector. A selector is not code. A selector is a name.

Maybe you could reformulate your question in a comprehensive manner,
as is it overly broad for me. Your sentence make as much sense to me
as "but if it is not really sending a message, why bother with the
C++ virtual function stuff? Why not just directly call our virtual
function via function calls?" would make to a C++ programmer.


Try to tell me how you would implement:

[a foo];

when you don't know the class of a, nor the avalaible
implementations of foo ? Can't you grasp that you need an extra
indirection (objc_msgSend) to get the objc semantic ?

Cheers,

--fred
Marcel Weiher
2000-12-15 09:17:05 UTC
Permalink
> I just had a thought - wouldn't it be nice if NSThread had a
method that
> allowed a nicer syntax for the above, using the same sort of
design as in
> the undo framework and Marcel's Higher-Order Messaging? So that we
could
> do something like
>
> [[NSThread detachWithTarget:foo] workWith:anArgument
> and:anotherArgument];

Why so complicated?

[[foo doAsynchronously] lotsOfWork:anArgument];

;-)

You could also have a version of -doAsynchronously that checks if
there are multiple CPUs available (and not busy) and resort to simply
returning self when no CPUs are available, thus taking advantage of
multiple CPUs when available, but on the other hand not causing
unecessary overhead when not. Ain't polymorphism grand? ;-)

Another nifty option would be to return a result, using 'futures':

notYetResult = [[foo futureCompute] lotsOfWork:anArgument];

To answer your question: this is pretty straightforward, all you
need to do is implement (hacked straight into Mail, no checking
done):

@implementation NSObject(asyncForwarding)

-doAsynchronously
{
id trampoline = [MPWTrampoline quickTrampoline];
[trampoline setXxxTarget:self];
[trampoline setXxxSelector:@selector(doInvocationAsync:)];
return trampoline;
}

-doAsynchronouslyIfBeneficial
{
if ( [NSHost lotsOfCPUsIdle] ) {
return [self doAsynchronously]
} else {
return self;
}
}

-(void)doInvocationAsync:anInvocation
{
[NSThread detachNewThreadSelector:@selector(doInvocation:)
toTarget:self
withObject:anInvocation];
}

-(void)doInvocation:anInvocation
{
NSAutoreleasePool *pool = [NSAutoreleasePool pool];
[anInvocation setTarget:self];
[anInvocation invoke];
[pool release];
}

@end

For computing with futures, all you'd have to do is implement a
FutureResult class, probably as a subclass of trampoline, that also
contains a lock/semaphore to block the calling thread if it tries to
access the result before the computation is finished, as well as code
in the async code to set the result when done and disable the lock.


Marcel
John Hörnkvist
2000-12-15 10:53:54 UTC
Permalink
> > A thread is only a locus of control. Fundamentally, the only
> > resources owned by a thread are register state and program counter.
> > There is some extra information _associated_ with a Cocoa thread,
> > among them the autorelease pool.
> > How can the object know in what thread it lives?
>
> The only other way would be to have one thread per object,
> or have an OS-level manager for this stuff.

Concurrent objects... I have a feeling that it trades a few simple problems for a lot of difficult ones. ;)

Isn't Fabrik a concurrent object oriented language in the Smalltalk tradition?

You can do it with Objective-C if you care to; just put each object in its own task or thread and let distributed objects handle the communications. I think you'll find that your system is too fine grained.


Something like this will make init create concurrent objects:
@interface ConcurrentObject:NSObject
{
pthread_mutexattr_t attr;
pthread_cond_t cond;
pthread_mutex_t* mutex;
}
@end

@implementation ConcurrentObject
- (id)init
{
NSPort *port1;
NSPort *port2;
NSArray *portArray;
NSConnection* connection;
pthread_cond_init(&cond,0);
pthread_mutexattr_init(&attr);
mutex = malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(mutex,&attr);

//NSLog(@"application did finish launching");

port1 = [NSPort port];
port2 = [NSPort port];

/* Ports switched here. */
portArray = [NSArray arrayWithObjects:port2, port1, nil];

[NSThread detachNewThreadSelector:@selector(runWithPorts:) toTarget:self withObject:portArray];

pthread_cond_wait(&cond,mutex);

connection = [NSConnection
connectionWithReceivePort:port1
sendPort:port2];

// Should free mutex...

return [[connection rootProxy] retain];
}

- (void) runWithPorts:(NSArray *)portArray
{
NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init];
NSConnection* connection;

connection = [[NSConnection alloc] initWithReceivePort:[portArray objectAtIndex:0] sendPort:[portArray objectAtIndex:0]];

[connection setRootObject:self];

pthread_cond_signal(&cond);

[[NSRunLoop currentRunLoop] run];
[pool release];
[NSThread exit];
}

@end

> [As an aside, did anyone do low-level programming under AmigaOS?

Yes. It has been a while...

> I seem to remember that it did "real" message passing, and used
> a special memory type for the message buffers (for MMU compat.)]

Message passing was very efficient, because there was no memory protection, so you just passed a pointer! Message passing was pervasive in AmigaOS. (It didn't cost anything, so why not...) Even in machines that had one, the MMU wasn't used, except by some debugging tools.

The Amiga had multi tasking from day 1 (time slicing with priority scheduling) but the OS didn't progress much from 1985 to 1994 when I stopped looking. The AmigaDOS part got rewritten from BCPL to C, so you didn't have to deal with BCPL pointers, but other than that, not much happened. Networking was always "going to be in the next release"... But I digress.

> Aah. I am confused again now. So, an objc_msgSend()
> _can_ actually send a message? (in contrast to invoking
> a function in a proxy which does its own messaging)

Could. Apple's implementation doesn't. But it could do that without changing the semantics of the language. (Apple's Objective-C runtime is a bit weak because it doesn't have type information for the arguments; that means it can't turn the message into a stream without help.) With help from the receiver [which can find out about the argument types] it can pack the message into an invocation object, which can be turned into a stream. The GNU runtime does carry type information with the selector, so there stream conversion would be much easier.

However, it is much more flexible to let objects handle the message transport, so I don't think objc_msgSend() should be changed to handle it...

As it is, we can quite easily do our own forwarding for any weird communications channel we can think of. Here is a very useless forwarder for a proxy that just sends messages over a pipe (fire and forget), before letting its superclass deal with it:
- (void)forwardInvocation:(NSInvocation*)anInvocation
{
NSData* messageData=[NSArchiver archivedDataWithRootObject:anInvocation];
fputs([messageData bytes],commandStream);
// Now do something reasonable with the
[super forwardInvocation:anInvocation];
}


Regards,
John Hornkvist

--
ToastedMarshmallow, the perfect Cocoa companion
http://www.toastedmarshmallow.com
Gregory Lightyear
2000-12-15 11:33:14 UTC
Permalink
On Friday, December 15, 2000, at 05:23 AM, ***@ind.tansu.com.au wrote:
> [As an aside, did anyone do low-level programming under AmigaOS?
> I seem to remember that it did "real" message passing, and used
> a special memory type for the message buffers (for MMU compat.)

I'm an ex-Amigan-developer. Even ran a technical journal (ARTJ) (and boy, does age show. I do believe that the photo of the editor was my navel and the photo of one of the other guys was an armpit, or something) towards the End of Days.

Message passing the way you're referring to was not very difficult under AmigaOS because quite frankly it didn't do a lot in the way of isolation. Mach does it the way you're thinking, though - it's one of the things that makes mach such a cool microkernel. Mach message-passing is entirely done with segments of shared memory and the whole kernel is built around providing that functionality. Can't say how much of the upper layers above it map directly to its functionality, though.

Speaking of which, does anyone know if the researched real-time extensions for media have been added to the Mach kernel???

> Yes, that is certainly the case for most languages.
> In this case, I guess I was hoping that Cocoa and Objective-C
> somehow did something different for the UI stuff.

Quite frankly, the UI would suffer *most* from that. The handling of the display is typically the one thing which most needs singlethread access in order to perform; even Be failed to build a system that didn't have that limitation.

> Well, except for the fact that I can draw UI stuff in one,
> and not in the other :-)

True of NeXTSTEP, Windows, OpenGL, and a million other user interface/display-driving APIs. Parallel UI is for the most part nonexistent.

> Thanks for your clarifications, John. Looks like it is time
> to re-read the manual, and to try and understand these examples:

I do highly, highly recommend the Concrete Protocols example as one of the "frighteningly cool things" that you can do through something like Objective-C that is difficult to accomplish with other languages.

A lot of people will rightly tell you, as well, that the cases for being able to swap out "live" methods on the fly, or to enable and disable methods within your class, are rare - and that's true so long as you're bound to your book of C++ patterns - but Objective-C can lend itself to a new set of patterns which, once able to use the true dynamic nature of the core, solve problems in beautifully elegant ways and often perform better than the multilevel-code-equivalent in other languages.

:plur,
Greg
Proof of Intelligent Life on Earth #357: Urinal mints.
Gregory Lightyear
2000-12-15 11:44:12 UTC
Permalink
On Friday, December 15, 2000, at 01:53 PM, John Hörnkvist wrote:
> Networking was always "going to be in the next release"... But
> I digress.

Not fair, it was. It wasn't released by Commodore, but their networking code *did* make it out as someone else's product. :) Actually, I used to watch the dev-team after they left; I saw DH go, but lost track of what haynie's been doing for the last few years (he was, when I was young, my inspiration - I think I grew up just like him. :) but I've located RJ Mical recently. :)

> stream. The GNU runtime does carry type information with the selector, so
> there stream conversion would be much easier.

Is there a cost impact to the GNU method vs. the Apple runtime? I'm curious to know whether any inherent value is present in having that type information available.

:plur,
Greg
I'll bet that 65% of everyone who reads this would kill a man for $4.00.
http://www.sonoma.edu/people/g/goodman/zimbardo.htm
John Hörnkvist
2000-12-15 12:21:50 UTC
Permalink
Gregory Lightyear wrote:
> On Friday, December 15, 2000, at 01:53 PM, John Hörnkvist wrote:
> > Networking was always "going to be in the next release"... But
> > I digress.
>
> Not fair, it was.

I lost track after Commodore went belly-up. Sold my Amiga 4000 for more than I paid for it a year and a half earlier. :)

> It wasn't released by Commodore, but their networking code
> *did* make it out as someone else's product. :) Actually, I used to watch the
> dev-team after they left; I saw DH go, but lost track of what haynie's been doing
> for the last few years


He worked at Scala, building their compiler, or something like that. I think Michael Sintz (sp?) brought him in. Then he became hardware developer for PIOS --- possible in his spare time ---where Dr. Peter Kittel and some other people also worked, but after that, the track went cold.

> (he was, when I was young, my inspiration - I think I grew up just like him. :)

With an A3000+ and attack trained cats in the garage? :)

> but I've located RJ Mical recently. :)

Cool. What does he the world's best janitor/hardware designer do these days?

Among the more talented Commodore alumni Ed Hepler does VLSI design/teaches somewhere. A shame he didn't get to finish Hombre. Way ahead of the Nintendos Ultra64 and Sony Playstation --- as an aside, Hepler or someone else in the Hombre team had already discussed Hombre with MIPS when Nintendo came. However, HP where more interested in allowing changes to the processor core, so Hombre went with PA-RISC. (IIRC, Hepler wanted to add "multi media instructions" to the processor pipeline.)

> > stream. The GNU runtime does carry type information with the selector, so
> > there stream conversion would be much easier.
>
> Is there a cost impact to the GNU method vs. the Apple runtime? I'm curious to know
> whether any inherent value is present in having that type information
> available.

I haven't measured. Helge Hess would probably know. You can't compare selectors with == any more, but on the other hand, code like
NSRect frame=[theView frame];
is safe, unlike Apple's implementation where you really have to check
NSRect frame = theView?[theView frame]:NSMakeRect(0,0,0,0);

But, you should probably do the check anyway, since the GNU runtime is slow when you call nil...

There is also some value in not having to implement
- (NSMethodSignature*)methodSignatureForSelector:(SEL)theSelector
in all forwarders.

Regards,
John Hornkvist



--
ToastedMarshmallow, the perfect Cocoa companion
http://www.toastedmarshmallow.com
Marcel Weiher
2000-12-15 17:44:17 UTC
Permalink
> From: John Hörnkvist <***@toastedmarshmallow.com>
>
> Concurrent objects... I have a feeling that it trades a few simple
problems for a
> lot of difficult ones. ;)

Yes! In fact, Smalltalk-72 started out with all objects being (sort
of) concurrent, co-routine based, but still... When you sent
messages, they didn't return results, the results were sent back to
you. Neat. However, it was a bit too much, in Smalltalk-76 they
simplified this to the current style of message-passing that looks a
bit like function-calling. However, they left in the DNU hook so you
could always get back to the full thing if needed.

> Isn't Fabrik a concurrent object oriented language in the
Smalltalk tradition?

Hmm, maybe there were several Fabriks, the one I know of is a sort
of visual programming lanuguage / interface-builder.

Marcel
John Hörnkvist
2000-12-15 18:14:39 UTC
Permalink
Marcel Weiher wrote:
> > Isn't Fabrik a concurrent object oriented language in the Smalltalk
> tradition?
>
> Hmm, maybe there were several Fabriks, the one I know of is a sort of visual
> programming lanuguage / interface-builder.

The language I'm thinking of used "card level" objects, and the semantics of messaging between cards was concurrent. I think Smalltalk-80 was used to build the "cards".

IIRC, the selling point was a visual development environment.

Anyway, there are plenty of concurrent object oriented languages; the Illinois Concert compiler with Concurrent Aggregates and Concurrent C++, for example. O'Haskell also comes to mind.

I don't think any of the concurrent languages I know of would make Cocoa programming any easier...

Regards,
John Hornkvist



--
ToastedMarshmallow, the perfect Cocoa companion
http://www.toastedmarshmallow.com
n***@ind.tansu.com.au
2000-12-18 21:26:43 UTC
Permalink
I asked:
> >[I wonder if it is just the lack of an autorelease pool that is
> > causing the draw-from-a-non-NSThread-thread failure, or if there
> > is some other Cocoa stuff missing. I couldn't tell from the trace]


Peter Bierman reminded us:
>
> Chris Kane answered this in a message to the list on 11/20:
...
> >AppKit is more or less thread-safe, but this safety is triggered by the
> >spawning of the first NSThread.


Thanks. I read that message at the time, but had forgotten
all about it. Interestingly, the technique works even with what
I thought would be an unsuccessfull NSThread creation:
pthread_create(...);
...
[NSThread detachNewThreadSelector: (SEL)""
toTarget: nil
withObject: nil]; // Allow pthread to access UI
(i.e. it doesn't need a valid selector and target)



This allows me to put up the error panel (no nasty signal),
but I still get the same autorelease warnings in this situation, so:

1) I assume that the autorelease pool has nothing to do with the
thread safety

2) Since it is a little messy to allocate a pool from the C function
that pthread_create() calls, it looks like NSThread is the best
way to do all of this



I do still wonder what is set up by the first NSThread.
The NSRunLoop doco implies that all [NS?]threads have a runLoop.
I assume it couldn't be the extra runLoop, though, since that would
probably go away when the thread exits?

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Greg Titus
2000-12-18 21:44:31 UTC
Permalink
> This allows me to put up the error panel (no nasty signal),
> but I still get the same autorelease warnings in this situation, so:
>
> 1) I assume that the autorelease pool has nothing to do with the
> thread safety

Right. NSAutoreleasePool's are per thread. The AppKit sets up its own
autorelease pool for the run-loop in its thread, but for any other thread
that you create (that might have objects autoreleased in it, at any rate),
the very first thing you should do is create an autorelease pool (and
release it at the end of the thread's function / method).

> I do still wonder what is set up by the first NSThread.
> The NSRunLoop doco implies that all [NS?]threads have a runLoop.
> I assume it couldn't be the extra runLoop, though, since that would
> probably go away when the thread exits?

Quite possibly a huge assortment of things get set up by the first
NSThread. It sends out the "NSWillBecomeMultiThreadedNotification" which
any number of classes or individual objects could be registered to receive.


There are quite a few situations where you might have a global cache of
some sort in a dictionary / hashtable / array / what-have-you, and if more
than one thread might be messing with that data structure, you need to
syncronize access with locks. There are many instances of this pattern in
our frameworks, for instance. In our particular case, we write enough
multi-threaded apps that we just expect to be multi-threaded and write the
code to always do the locking. If we wanted to be as polished as Apple, we
really should leave those locks as nil until we get a
will-become-multithreaded notification, and allocate the locks then. That
would make accessing these structures more efficient in the
single-threaded case where those locks aren't neccesary.

If we had used the notification that way, then there might be 10 different
unrelated locks and data structures that got initialized in just our code
when the first NSThread is created. Who knows how many there are in various
Cocoa classes.

Hope this helps,
Greg
n***@ind.tansu.com.au
2000-12-18 22:04:07 UTC
Permalink
Fred commented:
> I missed the start of this thread, but it looks like nigel still
> have the power to start threads that will not die (tm).

Sorry. I am not _trying_ to be overly argumentative.
It must just be a Friday afternoon thing!


I expounded:
> > but if it is not really sending a message, why bother with the
> > objc_msgSend() stuff? Why not just directly call our selectors
> > via function calls?
>
> You cannot call a selector. A selector is not code. A selector is a name.

Well, yes, but a selector is usually associated, via the
runtime environment, with a class's function, so it is close.


> Maybe you could reformulate your question in a comprehensive manner,
> as is it overly broad for me. Your sentence make as much sense to me
> as "but if it is not really sending a message, why bother with the
> C++ virtual function stuff? Why not just directly call our virtual
> function via function calls?" would make to a C++ programmer.

If [target selector] was called a "virtual method" then
I would agree that my argument and this are equally nonsensical.

But, most people call [target selector] a message, which
I am now slightly dissapointed to find out is not the case, and
probably never will be in Apple's runtime.



> Try to tell me how you would implement:
>
> [a foo];
>
> when you don't know the class of a, nor the avalaible
> implementations of foo ?

In C++, you can't. Maybe some virtual function table stuff
could be manipulated at runtime, but I wouldn't want to maintain it.



> Can't you grasp that you need an extra
> indirection (objc_msgSend) to get the objc semantic ?

I can grasp that, and I am glad that it is an "open"
part of the runtime. I can also see that having the power to
easily change any method via code or runtime (e.g. debugger)
is fantastic. It just isn't something I have had to directly
use yet.


My problem is (was) having to unlearn the idea that
the [target selector] syntax is passing a message.



I would currently explain it as "virtual function call"
or a "virtual method invocation." It probably _is_ different
enough to warrant its own syntax, but it does not actually seem
to result in sending a message, any more so than invoking a C++
method's function sends a message.

(though this is all semantically moot)



Does this explain where my questioning was leading?

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Helge Hess
2000-12-18 22:43:17 UTC
Permalink
***@ind.tansu.com.au wrote:
> > You cannot call a selector. A selector is not code. A selector is a name.
>
> Well, yes, but a selector is usually associated, via the
> runtime environment, with a class's function, so it is close.

No, this is not true. A class' function might be associated with a
selector, but not the reverse. A selector has nothing to do with
classes/methods on it's own, it's a higher level concept - seperate from
implementation concepts.
Eg
Vector *v; [v add:o];
and
Number *n; [n add:o];
and
JavaLangNumber *jn; [jn add:o];
All use the same selector (message identifier) 'add:'. In the third case
it isn't associated with a C/ObjC function at all, but dynamically
dispatched to the Java runtime.

One could say that a selector is associated with many functions of
different classes, but even this is not true, since a selector doesn't
need to be implemented by a ObjC/C function at all.

> But, most people call [target selector] a message, which
> I am now slightly dissapointed to find out is not the case, and
> probably never will be in Apple's runtime.

It's a 'message invocation'. The 'selector' is the message (in
combination with the arguments), 'target' is the receiver. The thing
which differs between a message and a function call is that a message
can invoke other stuff but functions.
The 'ORB' which dispatches the message is the -forwardInvocation:
function of NSObject/NSProxy.

> My problem is (was) having to unlearn the idea that
> the [target selector] syntax is passing a message.

I guess you need to explain what you consider a message (was this
explained earlier in the thread ?)
For me a message is a unique message identifier together with some
message data. This is exactly what is done in the above.

> I would currently explain it as "virtual function call"
> or a "virtual method invocation." It probably _is_ different
> enough to warrant its own syntax, but it does not actually seem
> to result in sending a message, any more so than invoking a C++
> method's function sends a message.

The major difference lies in the case when the target's class does not
implement the selector. Until that the ObjC message dispatcher indeed
works somewhat like a "virtual method invocation" since it accesses the
class' selector->method mapping tables directly. But in the case when
the class does not implement a method for a given selector, the object
becomes a 'mini-ORB' and is able to dispatch the message (the
NSInvocation object) on it's own (eg by archiving and sending the
message to another host or by calling a mapped Java method instead of an
ObjC one).

Greetings
Helge
Greg Titus
2000-12-18 22:32:15 UTC
Permalink
> My problem is (was) having to unlearn the idea that
> the [target selector] syntax is passing a message.

Hey Nigel,

I think the reason why Fred is asking you to reformulate your question is
because you seem to have a different conception of what the word "message"
means from some of the rest of us. Clearly it is a highly overloaded word.

The only computer related definition in the on-line dictionaries I have
(via OmniDictionary, plug plug) is from "The Free On-line Dictionary of
Computing" and states:

"In object-oriented programming sending a message to an object (to invoke
a method) is equivalent to calling a procedure in traditional programming
languages, except that the actual code executed may only be selected at
run-time depending on the class of the object. Thus, in response to the
message "drawSelf", the method code invoked would be different if the
target object were a circle or a square."

Hopefully we can all agree that by this definition, Objective-C is, in
fact, passing a message? So how would you define "message"?

Greg
n***@ind.tansu.com.au
2000-12-19 02:08:04 UTC
Permalink
I wrote:
>2) Since it is a little messy to allocate a pool from the C function
> that pthread_create() calls, it looks like NSThread is the best
> way to do all of this


Peter asked:
> Why is it messy?
>
> Just:
>
> void my_thread_entry(...)
> {
> NSAutoreleasePool *pool;
> pool = [[NSAutoreleasePool alloc] init];
>
> ...existing thread body...
>
> [pool release];
> }


Its that easy if the function is in a .m file, but if it is
in a C++ source file, there is a bit of objc_msgSend() and selector
caching required.

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
n***@ind.tansu.com.au
2000-12-19 02:40:57 UTC
Permalink
Greg clarified:
> I think the reason why Fred is asking you to reformulate your question is
> because you seem to have a different conception of what the word "message"
> means from some of the rest of us. Clearly it is a highly overloaded word.

Yes. When I hear message, I think of putting a letter in an
envelope and sending it via the postal service, or sending an SMS
message to a mobile phone via a telecommunications carrier (even if
the recipient is myself), or opening and writing to a Unix socket or
TCP/IP port.

I have always heard OO languages C++ described as Classes,
Objects and Methods, and never in messaging terminology, so when
I hear "sending a message to an object", I think of invoking a
transport layer to send data to a registered object.

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Rick Roe
2000-12-19 03:07:11 UTC
Permalink
Guess I'll insert my $1/50 as a near-total newbie:

I think ObjC's definition of the term "message" is a far more simple
semantic than you're making it out to be. When I write [myFooController
doTheFoo], I'm "telling" myFooController to doTheFoo. And the Speech
Communication majors would tell you that telling someone something is the
same as "conveying a message".

For example, right now I'm tring to convey to you the message that ObjC
messaging isn't as hard to grok as you think. :) And I'd still be "sending a
message" or "trying to get a message across" if we were talking face to face
instead of sending email messages back and forth.

> I have always heard OO languages C++ described as Classes,
> Objects and Methods, and never in messaging terminology,

Well, some on this list will probably be happy to argue that that says
something about C++. :)

--
Rick Roe
Webmeister & Icon Dude
http://www.icons.cx/
Gary Teter
2000-12-19 04:09:28 UTC
Permalink
on 12/18/00 8:39 PM, ***@ind.tansu.com.au at ***@ind.tansu.com.au wrote:

> I have always heard OO languages C++ described as Classes,
> Objects and Methods, and never in messaging terminology, so when
> I hear "sending a message to an object", I think of invoking a
> transport layer to send data to a registered object.

But surely you would want that transport layer to be as efficient as
possible, and when operating within a single process, what could be more
efficient than simply performing a (cached) lookup and calling a function?

I am not an ObjC programmer per se (Java is my bag these days lately, coming
from the WebObjects side of things), but it seems to me that ObjC allows for
both method invocation over a transport layer and function calling with the
same syntax, and isn't that a Good Thing, and consistent with
object-oriented principles?

I have to admit, my first exposure to OO programming was back in 1980 or so,
when Ted Nelson was editor of Creative Computing, so I understand what
you're saying -- my introduction was to Fred the Box, and let's tell Fred to
move 30, etc. -- but if you're looking for "pure" message passing where each
object lives in its own isolated execution context, perhaps you should
consider another language than ObjC, maybe Erlang or something.

PS: And before someone identifies me as a Java advocate, don't get me
started on why Java even has primitive types... jeez, why not, when you're
requiring a virtual machine, do it like SmallTalk to begin with?! But then
maybe I'm weird, I have a warm spot in my heart for Forth and occasionally
get the urge to write 6809 assembly code again, too....

> | Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
> | Telstra NW-D, Sydney, Australia. | when you stop believing |
> | Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
> | Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |

PPS: You know Phil Dick was a loony, right? :-)
(I just read Dr. Bloodmoney this week and loved Valis,
so Please Don't Hit Me!(tm) :-)

--
Gary Teter, Big Dog
Bulldog Beach Interactive http://www.bulldogbeach.com
Marco Scheurer
2000-12-19 09:25:38 UTC
Permalink
> I have always heard OO languages C++ described as Classes,
> Objects and Methods, and never in messaging terminology,

Yes, and that's too bad, because in fact the primordial thing is the
message! The what rather than than the how (the method).

If I remember correctly, one very good introductory book to OOP (An
Introduction to Object-Oriented Programming by Timothy Budd [1]) starts
with the idea of messaging. I think this also makes it clear that an
important feature of OOP is polymorphism, and that classification is only a
(limited) form of polymorphism.

[1] http://www.amazon.com/exec/obidos/ASIN/0201824191/sente


Marco Scheurer
Sen:te, Lausanne, Switzerland http://www.sente.ch
John Hörnkvist
2000-12-19 10:04:13 UTC
Permalink
Marco Scheurer wrote:
> I think this also makes it clear that an important feature of OOP is polymorphism,
> and that classification is only a (limited) form of polymorphism.

Indeed! Subtyping is really too weak for an object oriented language.

http://www.luca.demon.co.uk/Bibliography.html
> • Martín Abadi and Luca Cardelli. On subtyping and matching. [Abstract]
> - ACM Transactions on Programming Languages and Systems, 18(4):401-423, 1996.
> ©1996 ACM [US.ps] [US.pdf] [A4.ps] [A4.pdf]

LOOM (Bruce, Petersen, Fiech) is an object oriented language that uses matching exclusively.

The "id" type means that Objective-C doesn't need parametric polymorphism for polymorphic containers and such, but the addition of explicit polymorphism would make for much nicer typing.

Protocols make it possible to have well typed programs where classification break down; it can be seen as a limited form of matching.

Regards,
John Hornkvist

--
ToastedMarshmallow, the perfect Cocoa companion
http://www.toastedmarshmallow.com
Marcel Weiher
2000-12-19 11:32:42 UTC
Permalink
> From: Marco Scheurer <***@sente.ch>

> > I have always heard OO languages C++ described as Classes,
> > Objects and Methods, and never in messaging terminology,
>
> Yes, and that's too bad, because in fact the primordial thing is the
> message! The what rather than than the how (the method).

YES! Alan Kay, who might be regarded has having some say on the
matter, posted this messages a little over two years ago to the
Squeak mailing list:

From: Alan Kay <***@wdi.disney.com>
Date: 1998-10-10 07:39:40 +0200
To: ***@cs.uiuc.edu
Subject: Re: prototypes vs classes was: Re: Sun's HotSpot

Folks --

Just a gentle reminder that I took some pains at the last OOPSLA to try to
remind everyone that Smalltalk is not only NOT its syntax or the class
library, it is not even about classes. I'm sorry that I long ago
coined the
term "objects" for this topic because it gets many people to focus on the
lesser idea.

The big idea is "messaging" -- that is what the kernal of Smalltalk/Squeak
is all about (and it's something that was never quite completed in our
Xerox PARC phase). The Japanese have a small word -- ma -- for "that which
is in between" -- perhaps the nearest English equivalent is
"interstitial".
The key in making great and growable systems is much more to design
how its
modules communicate rather than what their internal properties and
behaviors should be. Think of the internet -- to live, it (a) has to allow
many different kinds of ideas and realizations that are beyond any single
standard and (b) to allow varying degrees of safe interoperability between
these ideas.

If you focus on just messaging -- and realize that a good metasystem can
late bind the various 2nd level architectures used in objects -- then much
of the language-, UI-, and OS based discussions on this thread are really
quite moot. This was why I complained at the last OOPSLA that --
whereas at
PARC we changed Smalltalk constantly, treating it always as a work in
progress -- when ST hit the larger world, it was pretty much taken as
"something just to be learned", as though it were Pascal or Algol.
Smalltalk-80 never really was mutated into the next better versions
of OOP.
Given the current low state of programming in general, I think this is a
real mistake.

I think I recall also pointing out that it is vitally important not
just to
have a complete metasystem, but to have fences that help guard the
crossing
of metaboundaries. One of the simplest of these was one of the motivations
for my original excursions in the late sixties: the realization that
assignments are a metalevel change from functions, and therefore
should not
be dealt with at the same level -- this was one of the motivations to
encapsulate these kinds of state changes, and not let them be done willy
nilly. I would say that a system that allowed other metathings to be done
in the ordinary course of programming (like changing what inheritance
means, or what is an instance) is a bad design. (I believe that systems
should allow these things, but the design should be such that there are
clear fences that have to be crossed when serious extensions are made.)

I would suggest that more progress could be made if the smart and talented
Squeak list would think more about what the next step in metaprogramming
should be -- how can we get great power, parsimony, AND security of
meaning?

Cheers to all,

Alan
Marcel Weiher
2000-12-19 11:47:38 UTC
Permalink
Hi,

the concept of messaging seems to repeatedly cause problems at least
for some newbiew (C++ background I would guess), maybe we should
organize a FAQ on this topic?

Here is a slightly edited version of an answer I posted recently to
c.l.objective-c. One dimension of variability that is missing is
that of receivers ( none, one, many, broadcast ), and a short
discussion of how the concept of parties in a communication (esp. the
receiver) doesn't really fit into the function-call abstraction.

Furthermore, the parameter space should be populated with more
examples (esp. in analogy to network communications protocols).
Finally, the wonderful explanations people have given of useful
things to do with messaging should probably be appended.

Does that sound like a good idea? Of course, it might cut those fun
threads short ;-)

Marcel


<MessageFAQ>
1. What is messaging? How is it different from a function call?

Messaging has several dimensions of variability, certainly at least
those of local/non-local, synchronous/asynchronous, early- vs.
late-bound. There is also the issue that a message can be
manifest (exist as an object or data structure) or implicit
in some action being invoked.

If you have local, synchronous, early-bound and non-manifest
messaging, you can implement that using a function call.

In Objective-C and Smalltalk, you add late binding and
enough run-time information that messages can become manifest.
The ability to deal with manifest messages makes it possible
to implement various other combinations (non-local, async.)
yourself.

So, to summarize: messaging is a very broad concept, and
calling-a-function can be viewed as a very special kind of
message-send. This type of message send is typically very
common and most systems optimize for it.

Other systems go the other way, instead of seeing a function-
call as a message send, they view that one kind of messaging
as a small extension of function-calling. However, this
leaves them without access to all the other modes of message
sending.

2. How is messaging useful?

- late binding, structural issues
- distributed objects
- language bridges
- undo manager
- higher order messages
- notificatiion centers
- ..

3. What do the experts say?
-> place to insert Alan Kay quote, possibly others

</MessagingFAQ>
n***@ind.tansu.com.au
2000-12-21 21:20:40 UTC
Permalink
I asked:
> I do still wonder what is set up by the first NSThread.
> The NSRunLoop doco implies that all [NS?]threads have a runLoop.
> I assume it couldn't be the extra runLoop, though, since that would
> probably go away when the thread exits?

Greg answered:
> Quite possibly a huge assortment of things get set up by the first
> NSThread. It sends out the "NSWillBecomeMultiThreadedNotification" which
> any number of classes or individual objects could be registered to receive.

Aah. Cool. Thanks.
So, if I did something like this:

[[NSNotificationCenter defaultCenter]
postNotificationName:@"NSWillBecomeMultiThreadedNotification"
object:self];
pthread_create(...);

then I could achieve the same thing?


OK. Now all I need to work out is a nice way to only do
this once in the application. (I could use a global BOOL, but there
should be a more elegant way)

--
| Nigel Pearson, ***@ind.tansu.com.au | "Reality is that which, |
| Telstra NW-D, Sydney, Australia. | when you stop believing |
| Office: 9206 3468 Fax: 9212 6329 | in it, doesn't go away." |
| Mobile: 0408 664435 Home: 9792 6998 | Philip K. Dick - 'Valis.' |
Continue reading on narkive:
Loading...