Be Developers' Conference

Advanced Messaging
Peter Potrebic

 

Peter Potrebic: Hi, welcome to the last technical session of the day. My name is Peter Potrebic, and this session is going to be on some advanced techniques using our messaging and Replicant systems. What I'm going to do is just talk a little bit about the BMessage object, which is at the core of a lot of functionality that's in the BeOS. And then I'm going to give you a few interesting, hopefully interesting ideas on some areas that you can explore in your own applications.

I'm going to talk about filtering of messages, archiving mechanisms and a couple areas of Replicants, which is something you heard about in earlier sessions.

The BMessage class is used for a lot of things in our system. It's basically a container object that you can use to store data. Both data with scalar type data, or your own types of data structures as well. And it's used in many areas of the system.

It's used for the event handling, mouse_down, key_down events get sent to your application as messages. It's also used for clipboard, when you move data into the clipboard or take data out of the clipboard you are using a BMessage object. It's used for inter- and intra-application communication. It's used in our archiving system as well and in the Replicants system. So it's really an important class to understand and to explore functionality.

The first thing I want to talk about is message filtering, there is really nothing too much, too new in R3 in terms of message filtering, but I wanted to kind of highlight the differences between filtering at the BHandler level or filtering at a BLooper level and the subtle but important differences.

As this is an extended track session, I'm kind of assuming that people have gotten, either through experience in programming the BeOS or through earlier sessions, an understanding of what a looper is and what a handler is.

A looper is a thread of execution that runs an event loop receiving the message and a handler handles the message. And the looper basically owns a set of handlers, just like a window contains a set of views. The views are handlers that live inside of the window which is the looper object.

So here we have an example of some message filter that we are going to use that's going to filter any key_down events going to any handler that belongs to the window. So we are going to be doing filtering at the BLooper level.

Did I skip a slide?

A Speaker: Yes.

Peter Potrebic: I did. So let me go back, first we will just talk about filtering just a single object, a single handler and this filter is going to filter all the keystrokes going to this one particular view. And you do that by creating a message filter object and you are just interested in key_down events, then you simply add that filter to the particular view that you are interested in. And from that point on whenever a key_down event is about to be given to this view, your filter has a chance of intercepting that message, doing something with it, transforming it or throwing it out, or just simply passing it on to the view and tallying up some information.

And now to this next slide, we are going to contrast that with filtering something at the looper level. And where that lets you filter an event again dealing with a key_down event, it's going to filter any key_down event going to any handler that belongs to that looper. And that's the filter1 variable, and that's created down here. Again, the same way, as in the previous slide, but now we use a function called AddCommonFilter. And by adding that to the window we are going to filter any key_down event linked to any view inside of that window. So it gives you a different level at which to intercept events. And a window being a handler itself, you can also call the function AddFilter, and this filter, object filter2, is filtering some arbitrary message type and you are only going to filter these messages going directly to the window, as opposed to any handler that lives inside of the window.

It's an important difference to remember, people who first start using filters often are confused, am I filtering at a looper level or at a handler level? So it's kind of an important distinction to be able to understand.

And some of the things you can use filtering for, you can use filtering as a form of security, and what this object is going to do, it's going to filter messages that are external messages. Messages that have come to you from another application. And you can do that by using a different constructor to the message filter class. And you specify that you are interested in messages that have a remote source.

This parameter here has a couple possibilities. There is a remote source constant, there is a local source constant, and there is an any source constant. I'm only interested in ones that came externally, so I would use the remote source constant, and I'm interested in messages that are delivered by any means and there are two possible means, there is programmatic means, someone has called the PostMessage or SendMessage function, that's programmatic, or there is drag and drop, when you drag and drop in our system, it's basically just sending a message. And so that message wasn't instigated with a send or a post, but a user drag and drop.

So there are two delivery mechanisms, but in this case I don't care if it was programmatically delivered or delivered through a drag and drop. So I created this filter and then I add it to my window and I'm using the AddCommonFilter because I'm interested in filtering messages that go to anything inside the window. So I use the Common API.

Now I'm going to move on to another topic. And that's archiving, and one possible use of archiving. Oftentimes in your application you need a little preference window. And in that preference window you have some state, maybe the cache size of whatever you are dealing with or the default font size for documents or whatever. You need to create code that makes this little window, than you need to write code that saves the particular preferences that the user has selected. And what I'm discussing here is using archiving, the archiving facilities in our system to actually archive the state of the whole window and use that as a way for also archiving the data that your preference window is setting.

Some of the benefits are that you are automatically saving and restoring of window position, it's another thing app developers always are faced with. Okay, I have a new window here, will I have to save the window position so it comes back in the same place? If you use archiving you get that for free. If you archive the whole window, and unarchive it, it will come back in the same exact location.

And it's also gives you a cross-platform storage mechanism, if your preferences for your particular application have a couple integer values, like default font size, and cache size, and you just write those two values out to a file, if someone takes that preference settings file and moves it onto another platform, you have to worry about endian issues. If you use the archiving system to store that data most of the endian issues are taken care of for you by the BMessage object.

A couple benefits to think about. This might not be the way you always do it, it's something to think about. If I use archive in this novel way, maybe it pays off in my application.

A Speaker: Is there problem when upgrading an application to newer version with potentially newer preferences?

Peter Potrebic: The question was, how would you upgrade an application if you did this? Even if you were just writing out your preference data as two longs and in the next release your preference is more involved and there are three longs, you would still have to support someone who has the data file that has a two longs, you would still have to handle that. And if you are just writing out a raw data structure and reading it back, you have to deal with it.

If you are using archiving, basically you are just using a message, you would still have to anticipate some information not being in a message because it's the older version. But it kind of gives you a nicer framework, I think, in terms of dealing with upgrading and I think it's also easier for downgrading. Because now if you added a third long to your data set in your preference, and the person goes back to the previous version and tries to launch the previous version, that old version is going to look at some data structure that now has three longs, and what if the order has changed, you are going to get gibberish. If you are archiving they will look in a message and will ignore the new entries in the message and they will still be able to find the old entries. So it might even be actually compatible in the other direction.

So here is the kind of code you might write if you wanted to archive your preference window. When the user opens up the preference window, changes the two settings for font size and cache size and they close the window, what you would do is you would want to archive that window; you create a BMessage and then you have some settings file where you are actually going to save the preference settings, so you create a BFile object. You take this, your window pointer, and you archive it into that message and then you take that message and flatten it out into this file. And that will take your window and put it into its archived flattened state.

And then undoing that part, rehydrating the window, so now the user has launched the application again, and you can actually do this first section here, you could do it before the window is needed because in this case we are actually using the window object as the internal API for getting the default font size and default cache size for our application.

So you would again go to that same file here, you would... and read out of that file and unflatten the message. And then use that to recreate your preference window object. And now you have this rehydrated window that contains the settings that were previously set by the user.

And then at some later point in the application maybe you actually have to get the cache size. So you just... your TPrefWind object has some function, get me the cache size, and you get it and it's just naturally the saved value because your window is archivable, you would... you can get back that cache size. When the user actually selects the preferences menu item to show the preference window you can show it. And then again do the archiving thing after they have made any changes.

So this is kind of, I mean there is more code you need to write for this to work, but this is just to give you a rough idea of what you need to do.

Now I want to talk a little bit about Replicants. There are a lot of new features in R3 in Replicants, a couple of those are dealing with the scripting, and then there is also a better concept of shelve having a particular type. And another new feature, which I will demonstrate a little later on, is the status view area in the desk bar.

The shelf_type, there was kind of a weak notion of shelving a type in PR2, it's a lot richer in the R3 release. Every shelf, or container view, has a type. And that type is a string. And a Replicant can also specify a particular type. And the Replicant specifies a particular type by adding a string entry named shelf_type to its archive message, with whatever type it wants to be.

So you have the container view having the notion of this is my type, and a Replicant having a notion of this is my type. A shelf can also enable and disable whether it's going to enforce the type, and by "enforce" I mean if a Replicant defines a particular type and the shelf doesn't have that matching type, then the Replicant will not be allowed to exist in the type.

And then the reverse is also true. If the shelf is enforcing its type, and a Replicant doesn't have the matching type, again the Replicant will not be allowed to live in that shelf or container view.

And one of the things you could use that for is implementing a tool bar or tool palette interface in your application. You could use, your little tool palette could actually be a container view and all of the tools that live in there could actually be Replicants.

And you can define a particular type which would prevent other kinds of Replicants from living... from being placed into your container view.

There is also a new call down here, SetAllowsDragging. You might decide that you don't want users to physically drag tools in and out of your tool palette and you can disable dragging with this SetAllowsDragging API.

And then you would present some other interface for a user to customize what tools they want to appear in a palette.

There is a lot of new scripting functionality in Replicants in R3. Every container view or shelf view automatically gets a property called Shelf, which gives you a way to interact with that view and find out, and interrogate what type of Replicants are living in that particular container view. And that's through a property called Replicant.

And you can do things like count, add and delete the Replicant and each Replicant gets a unique ID, when it's added to a container view, and you can save that unique ID and it's valid as long as that Replicant says in that container, across reboot or whatever, it creates a unique ID and you can use that later to work with your Replicant. I will give you a demonstration later of some of these features.

Let me go through this slide first, saying that the desk bar has a Replicant, has a container view area where you can add Replicants, the mail daemon currently puts a little icon in there, a little mailbox icon, and that's using this new mechanism. In PR2 it was using a private interface and we have made that interface public so developers can write applications that put Replicants in that area.

Here is the status area in the desk bar. And I'm going to start up the mail daemon, which puts an icon here in the status area. And that icon provides an interface, this is simply a Replicant. With the new scripting functionality I talked about I can ask the desk bar, I can send scripting messages to the desk bar in order to find out about it. I can send a message here and I get back a messenger object, which hopefully people are familiar with, and that gives me a conduit to send messages to that object. I can count here, I'm going to count the number of Replicants in that shelf. And I'm going to get back 1.

There is one object here. The clock here isn't actually a Replicant, it's just something that the desk bar decided to draw in this area, which I can hide if I want to.

I mentioned there is a unique ID, that Replicants that I added got a unique ID, so I can ask the Replicant zero for its ID. And I get back 1. And as other objects are added, they will get another unique identifier. And as I said, that identifier, as long as that icon is there that identifier will stay the same.

One of the interesting things you can do is you can also get that entire Replicant by just asking, which gives you the ability to actually take that Replicant that lives in one application and say you have an application, you have your own little status area and you also want to have that mailbox icon, you can actually extract that Replicant from that application and put it into yours.

What I have done here is just asked give me the Replicant, get me Replicant 0, and what I get back, and if anyone has played around with Replicant you will be familiar with the message, that basically defines that Replicant. So I can take that message in my own application, I can rehydrate that exact same user interface by simply making one API call. So the new scripting functionality is pretty powerful in the Replicant world.

A Speaker: So Peter, since Replicants have IDs, can you ask for Replicant by ID as well?

Peter Potrebic: Yes.

A Speaker: How do you distinguish, by asking for index?

Peter Potrebic: if you ask for ID it's a different specifier, different specifier type. Instead of asking for an object by index, like giving me the 0 or first Replicant by index, you would ask for it, I forget the keyword in the API.

A Speaker: So the Doo tool would have to have...

Peter Potrebic: The Doo tool does have... I did add support, here is a little help for my Doo tool. There is some syntax here. ":1", so I could say this object's ID is 1. So if I said Doo something ":1", that would mean the ID 1. And now the status area is a little tiny area, some of the new functionality that was added in R3, how does a little container view prevent images objects from being dropped in it and things like that? And there is new hook functions in R3 that allows a container view to interrogate objects before they are added to make sure that they will fit, so if in a desk bar case a imagesr icon, someone tried to add a imagesr icon, the desk bar would reject that and send back an error message.

And here is some sample code of how you go about actually adding Replicants to the desk bar. And you would write similar code if you had implemented a tool palette type architecture in your application you might have something similar to this, for adding tools to your palette. And you just create a BMessage, you take the object, this is the object, in the case of the desk bar this is that object that's a little mailbox icon that you click on and brings up a pop-up menu and you archive that object.

And now I created a BMessenger object which is a way to talk about objects living in other applications, and I created a BMessenger object and this is the signature for the desk bar application. And there is various ways to create these messengers, this is just one example where I'm using the signature of an application. And I just take the archived widget and I send it to the desk bar application. And the desk bar gets that message and it knows what to do with it, and that being hydrate the object and put it inside the status area. Of course assuming it fits, that there is still room, that the object isn't too big, if it had a type, that I talked about earlier, it would make sure the system would automatically make sure that the types matched so that everything is kosher and legit.

So because of all those requirements for size and spacing, you need to expect that or anticipate that it might not fit, or your icon is too big. So if that's the case, this reply message would contain any error information explaining what happened. And if it succeeded you would also get back that unique identifier that I talked about, and you can save that and use that to later on talk to your icon, telling it to change its appearance if something happened or whatever you... whatever ideas you might come up with.

A Speaker: Can you also get a messenger to that Replicant?

Peter Potrebic: Yes. The question was could you get a messenger to that Replicant? Yes, you can. I probably have that... well, my first example here was getting a messenger to the shelf. And I'm sure a similar Doo command would give you a messenger, you could say get messenger of Replicant zero of shelf.

Another thing that comes up occasionally on BeDevTalk, and people have asked me in the hallways here, is a Replicant necessarily something visual on the screen or what exactly is a Replicant and what isn't a Replicant? And in my mind, and maybe only in my mind, a Replicant isn't necessarily a view. There are really two things that make something a Replicant in my mind. One is that it can be archived and unarchived using some of the code that I have shown you here.

The other is that it has in that archive, it has a special piece of information that gives the system a pointer to where the hunk of code is that knows how to create that object. And if you put those two things together, to me that makes a Replicant. So it really has nothing to do with being visual. And if I... I will go back here and show you.

When I ask the status area here, I ask this object to give me the message to itself, this is that archived message for the mailbox icon. And you will see down here, I believe it is, there is one hunk of data called "add-on", and the value is an application signature. And that's the signature of the application, of the executable code, that knows how to take this pile of data here, that looks like gibberish, it knows how to take that and recreate a real object in the BeOS. And in this case it's a view object. And that's what creates this little visual entity that you see here. So it's this... this is that second piece of information, this is that pointer that tells the system where the executable code is. And we do that via application signatures.

So it doesn't really have to be specific to anything graphical. And one possible example is you could have an extensible math engine that wants to have an extensible library of functionality for doing different types of calculations, and it could decide that I'm going to use the Replicant API, if you will, to be extensible. So this math engine would say here is my interface and that interface would be a C++ API that descends from a system class called BArchivable, and then developers interested in adding further math functionality would use that API, subclass it, add their particular calculations to that object, and that would be a way for creating an extensible math engine.

The actual user interface, if it had one, for the math... the mathematical calculations would take these applications or plug-ins and load them dynamically as Replicants, they wouldn't have any necessarily graphical user interface. You could also programmatically, just like the example of when I first launched the mail daemon, magically the mailbox icon appeared. That's because the mail daemon writes code like this that executes, when it gets launched you could have programs just dynamically sending new math libraries to this math engine when the user did something. And this would give you a basically a nonview based Replicant architecture.

So think about it, so there are some interesting possibilities for using this API. It's basically a plug-in add-on API, but instead of arbitrarily defining entry points it gives a structured place and structured API for loading things, for finding the appropriate entry points to create the objects that you are interested in talking to.

So that's about all I had to talk about today. Hopefully you guys will have interesting ideas. If you want to bring up some of those ideas now or had questions on what I talked about, I'm here to answer any questions.

You had a question here? Oh, you didn't?

A Speaker: So it seems that this thing you are recommending is very similar to the other add-on structure that you have except that the code possibly lives all over the place instead of one place that the application is fetching it from. Is there any way to know somebody is using the code in this application?

Peter Potrebic: I'm not sure about... you said it's similar to the other add-on API?

A Speaker: The sort of drag and throw add-on code in the directory and then a certain application will look in that directory.

Peter Potrebic: Well, this... so the question was, well, part of the question was is this different from or... from the... in our file system we have some recommendations and some well-known places where we look for add-ons inside of the user folder, in the BeOS folder we look for add-ons and that's where add-ons get loaded if an application is interested in them, how is this different? This might well be the same because an application that is using add-ons doesn't just load every add-on in that folder, it wants specific add-ons that make sense for it. So this extensible math library wouldn't load every add-on, it would load specific add-ons that were in the add-ons folder in some subfolder it defined, saying this is where you put math engine add-ons.

So there is no difference there, I think, and then you had some more...

A Speaker: We can talk about it later.

Peter Potrebic: Okay. Any other questions?

A Speaker: Where you had that example using SetAllowsDragging, from reading the BeOS manual, the one that's on sale in the room over there, that made it sound a lot like what settled out dragging does after the Replicant has been dropped on the shelf, it allows or disallows the user to change position. What you said, unless I misunderstood you, you sounded like it controls whether they are allowed to drag and drop the Replicant in the first place.

Peter Potrebic: The question is what the does SetAllowsDragging API do? It prevents a user from dragging an object into the container view and once an object is in that container view, it prevents dragging within that container view or back out of that container view. So SetAllowsDragging disables the dragging in either direction.

A Speaker: Okay. So there is no way to tell yes, they can drop objects onto the container view but once they are dropped using some other functions it's going to reposition them where it wants, after that they can't...

Peter Potrebic: Right. Using the SetAllowsDragging call, yes. Now a container view could say as things are dropped on me, I'm going to position them like so. And if one gets deleted through some mechanism I'm going to reposition them, you know, to fill in the hole. That's easy to do with the container view API. There are hook functions in there that you would override so that you would know when something was deleted and you could relay out things.

A Speaker: Is there any way to stop the user from repositioning something?

Peter Potrebic: If you disabled... you would, for that type of container view you would disable...

A Speaker: But then you can't drag new ones on. I'm looking for something if he drags something container view decides where it is to be put. He should be able to drag and drop but he couldn't move things already on there.

Peter Potrebic: So the question is, he envisions a container view where a user could drag something onto the container view and drop it, but once they let go, that's it. It might get repositioned, and then once it's positioned a user can no longer muck with that. And I bet you could do that but I... I bet you could do it with the existing API, you would probably not use SetAllowsDragging, you would probably have to override some other things and it's a useful suggestion to make that functionality easier.

A Speaker: Okay, because that was what I thought SetAllowsDragging...

Peter Potrebic: No.

A Speaker: In debugging, how come all of a sudden I can't drag...

Peter Potrebic: That's a good suggestion.

You had a question?

A Speaker: Yes. I was going to ask about archiving. Now, how pervasive is archiving through the system? I mean, I'm a little unsure about it. Is it something that I have to still call from the archive... I have to initialize archiving on objects when I build them, I... when I build a window or view I have to say this is archivable?

Peter Potrebic: The question is how pervasive is archiving? I guess there are two answers to that. One is all of the objects, all the interface kit type objects are archivable. So if you build a window and in that window you add a bunch of just generic buttons and view and BeBoxes and menus and scrollers and things like that, you can take that whole window, archive it, unarchive it, and you are back to where you were before. You don't have to really do anything.

If you then, say you wanted a fancy button, so you subclass the button and then fancy button has some extra state that tells you something, you would need to... to also archive that information, so that when it got unarchived, so your subclass would have to do a few things in order to fit in with the archiving to be archiving savvy, and once you did that, then your subclass would be archivable and it could live in any window and it would archive and unarchive the same.

Does that answer your question?

A Speaker: So I'm going to inherit some things?

Peter Potrebic: Right. Anything you add. So if your subclass has some data members and those data members are somehow part of the real state of the object, not just some temporary thing, those are the types of things that you would probably need to archive.

A Speaker: Okay. So in our example preferences...

Peter Potrebic: Right. Right. Exactly. The preference window had two values, a font size and a cache size, you would, at the window, your subclass of BWindow that TPrefWind object would override the archive function and store those two values in the archive message and then the rehydration would get those two values out of the BMessage and initialize the data members.

A Speaker: So I would still be doing that but I wouldn't have to worry about the endian issues.

Peter Potrebic: Right. And BMessage for standard data types, reading and writing all the endian issues are handled. So you can read and write floats, rectangles, things like that.

A Speaker: I had a dumb end user question. Is there any way to make the browsing through directories able to open windows in windows instead of just opening a hundred million windows all over the place?

Peter Potrebic: We know about that feature, but you can ask Pavel in a general Q and A.

A Speaker: Okay.

Peter Potrebic: We know about that feature.

A Speaker: What was the question?

Peter Potrebic: What was the question? The ability to open a Tracker window within Tracker, like reusing the existing window. We know about that feature. That's Pavel. Let's see. But wait, we have to figure out how to do it with scripts, messages and Replicants, because we are in this session.

A Speaker: What you do is you set up a script to send a message to Pavel to insist he put it in...

Peter Potrebic: There was a hand over here.

A Speaker: Is it possible to 2 things archive into the same file?

Peter Potrebic: The question was is it possible to archive more than one window into the same file? Yes, it is. You would just initialize your file object and archive the first window, write it out, archive the second window, write it out, it would be your code that would know, okay, when I'm reading it back in there is one window and after it was done reading the next, the file pointer is going to be at the right place and you stream in the other one.

A Speaker: How about scripting across the network? This is something I was thinking about as well. So we have got a couple of machines on the network, now I want to write a script that changes the state of the application that's running on a different machine. So now in current state when you talk about specifying, specifying things that are all on the same machine, do we have any network type specifiers or do I have to write my own?

Peter Potrebic: The question was what about scripting across machines? We saw some examples of frame of view 1 of some window and shelf status, everything was just within the same machine. What about across machines? Right now there isn't any built-in support for that in the BeOS, but all of this stuff was done with that kind of functionality in mind. The general messaging model of a BMessenger object being able to point to anything on a particular machine when we were working on that, having a messenger that points to an object on another machine, that was in our minds. The scripting architecture and specifiers, all that stuff being able to span or address things across machines, we also thought about it. So it's not something we support now, but it's definitely something we think is good. And we will get to it as quickly as we can.

A Speaker: You mentioned in the definition for a Replicant it had to be something that could be archived and unarchived, and has to include an add-on reference to the hunk of code.

Peter Potrebic: Right.

A Speaker: What does the hunk of code have to be? Application, a Tracker add-on, a...

Peter Potrebic: The hunk of code from the Replicant perspective just has to have... basically it's an add-on. It's not a Tracker add-on, it's just a hunk of code that has a particular entry point.

I don't know if I repeated the question. The question was the hunk of code that defines this... that understands this Replicant, what is it? Is it an application or a Tracker add-on or what is it? And the answer is it's just, from my perspective in Replicants all it is is an add-on that follows the BArchivable API.

A Speaker: I guess my question from the compiler's point of view, what is it?

Peter Potrebic: From the compiler's point of view it can be all three, as in Pavel's, some of the people probably were in Pavel's talk about communicating with Tracker, he showed an example where he made a Tracker add-on and he also made that same add-on also an application. And you could have it also be a hunk of code that has a Replicant or multiple Replicants in it, so it can be all of them, it can have a name and be an application, it can have the interesting entry point that Pavel wants to be a Tracker add-on, and it can have the interesting BArchivable API so that it is a Replicant or defines some Replicant.

A Speaker: Okay. So it could be just an application which has this additional entry point?

Peter Potrebic: Yes.

A Speaker: And that is documented?

Peter Potrebic: Yes. Yes, in the Be Book when it talks about Replicants it explains that you need to export... part of the BArchivable API is to make sure that the particular important symbol is exported from your hunk of code just like you have to do, in the Tracker add-on case you have to export the particular entry point that the Tracker looks for. In the Replicant it looks for a particular entry point as well. And the Be Book talks about that. And how you would implement that.

A Speaker: Okay, thank you. I think I just figured out why mine isn't working.

Peter Potrebic: That's what we are here for.

Any other questions?

A Speaker: I kind of see that the add-on stuff is almost in reverse if you were to use Replicant technology without a view where you could have an application that you want to install, let's say a filter or something like that, and you could have this thing install itself on like a user program while it's running and then that program doesn't have to search out and find it because you can let it use the Replicant, automatically go out and use what's inside the self class as like some sort of like a pointer in the code or something like that, so that's a viable thing rather than having to search through an add-on directory and find the add-on through that sort of route, you could say filters using program X basically install themselves by putting their views list Replicant into the shelf of that program.

Peter Potrebic: Yes. I hope there wasn't a question in there.

A Speaker: No, no.

Peter Potrebic: Yes, you can do that type of stuff. Hopefully most people heard everything that he said. But yes, you can do that type of stuff.

A Speaker: I guess one last question. The entry point you are talking about is static Instantiate() function?

Peter Potrebic: He says what's the actual entry point? Yes, it's the static member function of any replicantable archivable object. It is the Instantiate member function. A static Instantiate member function.

A Speaker: There was something in one of the BInfo discussions recently that stated when you export entry points and add-ons and things like that, in order to avoid cross-platform problems you should (inaudible) C in order to avoid different name mangling.

Peter Potrebic: The question was name mangling issues versus the compilers on PowerPC versus compilers on Intel. That might be the only place in my personal code and one of the few places in the system that is platform dependent. You, as an application developer writing a Replicant, don't have to worry about that.

A Speaker: You don't have to worry about mangling?

Peter Potrebic: No.

A Speaker: Thank you.

Peter Potrebic: The compilers mangle it to whatever platform you are compiling for, and the BeOS looks for the right symbol on the right platform and there you go.

A Speaker: Thank you.

A Speaker: I think the object (inaudible) for the Replicant.

Peter Potrebic: Wait. Can you start again?

A Speaker: Does the instantiate object look for the Replicant entry point also in the table of contents on PowerPC? I was under that impression.

A Speaker: Does it look through already loaded symbols?

Peter Potrebic: Right now that's an area that I'm thinking... the question was where does it look for the symbols? The right entry point, does it look in already loaded libraries or not? And that... I worked on that some for R3 and I can't remember exactly what I did, but I know there is some issues with that. And so it's better.

And then another thing to think about along those lines, you might want a Replicant to load a particular library and then say someone instantiates the same Replicant a second time. Maybe you want that library to be loaded a second time or maybe you want it to reuse the already loaded image. And both possible scenarios make sense, depending on what your Replicant is. So a feature I see implementing sometime down the road is having the archive describe I want my add-on to be loaded every time I'm instantiated, or if it's already loaded you can reuse that existing already loaded image. And that is further allowing you to refine and do different types of things in Replicant.

A Speaker: Does the Intel version have a table of contents?

Peter Potrebic: Yes. The question was, on Intel could you look for already loaded symbols, and the answer is yes. If you didn't, none of this would work.

Any other questions? All right. Then the last thing, last official thing is the Q and A session at 5:00. And the Masters Awards. So don't forget to go. Especially if you submitted. And you get to beat up on all of us engineers one more time.

Thanks a lot.

(Applause.)