From: Mike R. <mik...@gm...> - 2007-08-31 00:26:02
|
My plan for checking for message handlers in instantiable classes will not suffice. I implemented the algorithm completely, only to find that I began with an incorrent implicit assumption. Specifically, I assumed that sizeof (SomethingClass) would be exactly sizeof (SBaseClass) + sizeof (all_its_interfaces) + number_of_messages * sizeof (void*). No dice. For efficiency, compiler implementations are allowed to pad structs, or leave extra space between members. For example, I added some members to SFileClass, and then removed them, but its size remained constant at 192 bytes. The result is that we can't treat every set of 4 bytes as a pointer, as some bytes are actually padding. As far as I can tell, this means that there is no way to check for all message handlers at class initiation time. We have to wait till the message is sent and then check if it is handled. This is bad for speed when typechecking is on, but more importantly, it's bad for catching errors earlier. Still, I'll try to think of a way. The good news is, the actual process of finding a message is now optimized more effectively. Also, our interfaces now beat Java in that we can provide default implementations. Take a look at the Java docs for SObject.clone() and the Cloneable interface, and you can tell it's a mess. You can also tell that the reason it's a mess is that they want to include a default implementation of clone() but only for Cloneable objects... It's definitely ugly. In our implementation, implementing SCloneable guarantees that you can obtain a clone. To make it a deep clone, you just need to handle the message SCloneable::distinguish, which lets you distinguish a clone from the source object. This would typically be done by replacing pointers to the source's member objects with pointers to fresh copies of the source's member objects. (For example, SString's distinguish allocates its own new character array and copies the source's string there.) For a derived class to add to its parent class's distinguish handler, it should handle SCloneable::distinguish with a function that starts with something like s_super_msg (obj, SCloneable, distinguish). s_super_msg() sends a message treating obj as the immediate parent type of its actual type. This way, message handlers can chain up, adding behavior rather than replacing it. So, it's great that we include default handlers, but it's definitely a shame that we can't check for message handlers (yet?) at class initiation time. -Mike |
From: Dan R. <sta...@gm...> - 2007-09-01 00:37:30
|
Is there a way, perhaps by using preprocessor defines or something, to check that interfaces have been implemented at compile time? Perhaps the compiler could spit out warnings (or halt?) if this were encountered? At least this way, the programmer would know if he/she were lazy and forgot to implement something. (Since, as we know, one use of interfaces is to keep the programmer on top of things.) As for default implementations, I'm a little confused. How can an interface have a default implementation if one doesn't know anything about the objects that can implement it? The interesting thing about interfaces is that they allow you to lump various objects together by the actions they perform even if they are not part of the same hierarchy. So I'm a little perplexed how what you have described works. I might just be missing something here, so please explain if you can. On 8/30/07, Mike Richman <mik...@gm...> wrote: > > My plan for checking for message handlers in instantiable classes will > not suffice. I implemented the algorithm completely, only to find > that I began with an incorrent implicit assumption. Specifically, I > assumed that sizeof (SomethingClass) would be exactly sizeof > (SBaseClass) + sizeof (all_its_interfaces) + number_of_messages * > sizeof (void*). No dice. For efficiency, compiler implementations > are allowed to pad structs, or leave extra space between members. For > example, I added some members to SFileClass, and then removed them, > but its size remained constant at 192 bytes. The result is that we > can't treat every set of 4 bytes as a pointer, as some bytes are > actually padding. > > As far as I can tell, this means that there is no way to check for all > message handlers at class initiation time. We have to wait till the > message is sent and then check if it is handled. This is bad for > speed when typechecking is on, but more importantly, it's bad for > catching errors earlier. Still, I'll try to think of a way. > > The good news is, the actual process of finding a message is now > optimized more effectively. Also, our interfaces now beat Java in > that we can provide default implementations. Take a look at the Java > docs for SObject.clone() and the Cloneable interface, and you can tell > it's a mess. You can also tell that the reason it's a mess is that > they want to include a default implementation of clone() but only for > Cloneable objects... It's definitely ugly. > > In our implementation, implementing SCloneable guarantees that you can > obtain a clone. To make it a deep clone, you just need to handle the > message SCloneable::distinguish, which lets you distinguish a clone > from the source object. This would typically be done by replacing > pointers to the source's member objects with pointers to fresh copies > of the source's member objects. (For example, SString's distinguish > allocates its own new character array and copies the source's string > there.) For a derived class to add to its parent class's distinguish > handler, it should handle SCloneable::distinguish with a function that > starts with something like s_super_msg (obj, SCloneable, distinguish). > s_super_msg() sends a message treating obj as the immediate parent > type of its actual type. This way, message handlers can chain up, > adding behavior rather than replacing it. > > So, it's great that we include default handlers, but it's definitely a > shame that we can't check for message handlers (yet?) at class > initiation time. > > -Mike > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? Stop. > Now Search log events and configuration files using AJAX and a browser. > Download your FREE copy of Splunk now >> http://get.splunk.com/ > _______________________________________________ > Sooc-devel mailing list > Soo...@li... > https://lists.sourceforge.net/lists/listinfo/sooc-devel > |
From: Mike R. <mik...@gm...> - 2007-09-02 17:57:20
|
The thing about messages is that they are totally dynamic: you generally connect them in s_class_implement() or its brethren, but you can (re)connect them anywhere in the class implementation. So it seems to me that checking that all the messages are connected needs to be dynamic also. Regarding default implementations... some of an interface's default handlers can operate in terms of other messages (which may or may not have default handlers) of the same or of inherited interfaces. SCloneable /does/ assume that it's dealing with an SObject, but I feel like that's valid. Let me know if/why you disagree. -Mike |
From: Dan R. <sta...@gm...> - 2007-09-02 18:05:23
|
I'm sorry...i'm a little confused by your explanation. On 9/2/07, Mike Richman <mik...@gm...> wrote: > > The thing about messages is that they are totally dynamic: you > generally connect them in s_class_implement() or its brethren, but you > can (re)connect them anywhere in the class implementation. So it > seems to me that checking that all the messages are connected needs to > be dynamic also. > > Regarding default implementations... some of an interface's default > handlers can operate in terms of other messages (which may or may not > have default handlers) of the same or of inherited interfaces. > SCloneable /does/ assume that it's dealing with an SObject, but I feel > like that's valid. Let me know if/why you disagree. > > -Mike > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? Stop. > Now Search log events and configuration files using AJAX and a browser. > Download your FREE copy of Splunk now >> http://get.splunk.com/ > _______________________________________________ > Sooc-devel mailing list > Soo...@li... > https://lists.sourceforge.net/lists/listinfo/sooc-devel > |
From: Dan R. <sta...@gm...> - 2007-09-03 04:19:46
|
Mike, Alright, so I actually looked at the code for SCloneable, and now I understand what you're talking about. The idea behind these default implementations is to allow messages to, by default, depend on other messages. One application, as you have demonstrated, is to minimize the number of messages an "implementor" actually needs to handle. As you explained before, all an object has to do to be fully cloneable is handle the "distinguish" method. The default handlers in the SCloneable interface take care of the various types of cloning. This is possible because the default handlers work with the memory directly without depending on the specifc methods or variables of a given object. So, this default implementation concept will work as long as the programmer is broad enough when writing them. It definitely works for SCloneable. I'd be a little nervous for other custom-made interfaces. One problem I can foresee is how this technique might encourages a programmer to lock an interface to a particular class hierarchy. In other words, a programmer may feel encouraged to create an interface with default handlers written in terms of SClock, expecting this interface to only be used for SClock and its children. This is sloppy programming of course, since it would make more sense to include Clock-specific code in SClock itself. Still, the programmer could abuse the interface system in this way if he/she wanted. This sort of interface-locking seems to border on multiple inheritance in the way it could force an interface to actually be part of the inheritance tree (albeit a very strange sort of branch). Okay, on second thought, it's not really locking. I neglected to consider the fact that the programmer has the option of implementing his own handlers for any message that has a default behavior. So, no matter what, an interface cannot be locked to a specific portion of the inheritance tree. Still, this doesn't change the fact that an interface can function, by default, as part of that tree. I'm not exactly sure what I think of this. Interfaces are very safe in Java in that they are merely frameworks. An interface will only be functional if a programmer makes sure to implement every piece of it. The programmer never has to think about what the interface will do if he chooses not to implement various pieces because it is simply useless in that state. In sooc, the programmer needs (or at least ought) to know how a particular interface behaves by default. He/she can change this behavior to suit his/her needs, but this is an extra decision that needs to be made each time an interface is implemented. And it becomes more confusing, I think, when the defaults don't assume SObject and only methods/messages associated with SObject. In any case, I'm not necessarily saying that what you've created is a bad idea. It's obviously relatively powerful in that you can essentially give a whole bunch of new functions to an object just by handling one message. I'm just wondering if what we have here is really that clean. In the case of SClone, SObject itself could implement the SCloneable messages in a manner identical to the current defaults. On the surface, this would result in the same functionality. Users would still only have to "override" the distinguish message in order to make deep clones work for a specific kind of child. In this model, interfaces remain simply frameworks, as in Java. It is up to various branches of the class hierarchy to determine the default behavior of an interface. And if there is a behavior that really ought to apply to allobjects, then it can simply be hard-coded into SObject. Children can still override these behaviors if required. The point is, the interface is free to remain a specification rather than a "suggested implementation," if you will. I wonder if it might be more in the spirit of sooc to limit default behaviors to class definitions. This way, a programmer is not encouraged to tie some behavior to the interface definition and then forget months later where it is indicated that Clocks should behave a certain way when the Strokeable::stroke message is called and GolfClubs seem to not understand how to do it by default (and, in fact, freak out because a Clock stroke has nothing to do with a golf stroke). (Srokeable is, of course, a horrible use of interfaces, but I think it helps explain my point.) Hopefully, I'm not grossly misunderstanding something here. So just take this as food for thought and eventually let me know what you think. --Dan P.S. Golfing should always be less dependent on time... On 9/2/07, Dan Reinish <sta...@gm...> wrote: > > I'm sorry...i'm a little confused by your explanation. > > On 9/2/07, Mike Richman <mik...@gm... > wrote: > > > > The thing about messages is that they are totally dynamic: you > > generally connect them in s_class_implement() or its brethren, but you > > can (re)connect them anywhere in the class implementation. So it > > seems to me that checking that all the messages are connected needs to > > be dynamic also. > > > > Regarding default implementations... some of an interface's default > > handlers can operate in terms of other messages (which may or may not > > have default handlers) of the same or of inherited interfaces. > > SCloneable /does/ assume that it's dealing with an SObject, but I feel > > like that's valid. Let me know if/why you disagree. > > > > -Mike > > > > > > ------------------------------------------------------------------------- > > This SF.net email is sponsored by: Splunk Inc. > > Still grepping through log files to find problems? Stop. > > Now Search log events and configuration files using AJAX and a browser. > > Download your FREE copy of Splunk now >> http://get.splunk.com/ > > _______________________________________________ > > Sooc-devel mailing list > > Soo...@li... > > https://lists.sourceforge.net/lists/listinfo/sooc-devel > > > > |
From: Mike R. <mik...@gm...> - 2007-09-03 06:44:22
|
It sounds like there are good reasons for Sooc to have interfaces that can have partial or (maybe) complete default implementations, and other good reasons for Sooc to have interfaces that forbid default implementations. Maybe it should allow both? I haven't thought this through completely, but maybe there can be something like s_iface and s_pure_iface. Pure interfaces would forbid any default implementations either by providing no means of connecting handlers or by zeroing the whole iface at the end of its init function. Also, regardless of how interfaces end up working, I think it might be nice to have a debugging mode at runtime. It can be on or off. When it's on, each class will track where its messages are connected. User code could then do something like s_dbg_msg_connections (stream, Class). There could potentially be other debugging help when debugging mode is on. This message tracking will be non-trivial to implement, though. -Mike |
From: Dan R. <sta...@gm...> - 2007-09-03 14:32:51
|
Multiple interface types seems kind of hefty, but I'll let you think about it some more. On 9/3/07, Mike Richman <mik...@gm...> wrote: > > It sounds like there are good reasons for Sooc to have interfaces that > can have partial or (maybe) complete default implementations, and > other good reasons for Sooc to have interfaces that forbid default > implementations. Maybe it should allow both? > > I haven't thought this through completely, but maybe there can be > something like s_iface and s_pure_iface. Pure interfaces would forbid > any default implementations either by providing no means of connecting > handlers or by zeroing the whole iface at the end of its init > function. > > Also, regardless of how interfaces end up working, I think it might be > nice to have a debugging mode at runtime. It can be on or off. When > it's on, each class will track where its messages are connected. User > code could then do something like s_dbg_msg_connections (stream, > Class). There could potentially be other debugging help when > debugging mode is on. This message tracking will be non-trivial to > implement, though. > > -Mike > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? Stop. > Now Search log events and configuration files using AJAX and a browser. > Download your FREE copy of Splunk now >> http://get.splunk.com/ > _______________________________________________ > Sooc-devel mailing list > Soo...@li... > https://lists.sourceforge.net/lists/listinfo/sooc-devel > |