Thread: [Pyobjc-dev] Calling methods on nil
Brought to you by:
ronaldoussoren
From: Dinu G. <gh...@da...> - 2003-05-06 14:11:07
|
Ok, I'm looking deeper into the documentation.... so here we go! Item 2 in pyobjc/Doc/warts.html currently says: In objective-C it is valid to call methods on nil, these calls will be ignored. The nil 'object' is mapped to None and None will not ignore method calls, but will most likely raise an AttributeError. You'll have to remember this when translating from Objective-C to python. This might lead to people who are trying to convert Cocoa code to Python to change the application logic. I remember I wrote a Null class that would behave as much as a "black whole" as possible. It's in the O'Reilly Python Cookbook and available online here: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 This might benefit from some more detailed inspection using ver- sion 2.3 of Python, which I haven't done, yet. I might be possible to replace the current None (as currently con- verted from nil) with a singleton Null instance, possibly as an option only, if the code rewriting ever becomes more of a real issue... I know that it can be very convenient in some cases if "nothing" happens in a well-defined way! ;-) Regards, Dinu -- Dinu C. Gherman ...................................................................... "Les gens se divisent en deux cat=E9gories=A0: les uns cherchent et ne trouvent pas, les autres trouvent et ne sont pas contents." (Mihail Eminescu)= |
From: Just v. R. <ju...@le...> - 2003-05-06 14:18:43
|
Dinu Gherman wrote: > Ok, I'm looking deeper into the documentation.... so here we go! > Item 2 in pyobjc/Doc/warts.html currently says: > > In objective-C it is valid to call methods on nil, these calls > will be ignored. The nil 'object' is mapped to None and None > will not ignore method calls, but will most likely raise an > AttributeError. You'll have to remember this when translating > from Objective-C to python. > > This might lead to people who are trying to convert Cocoa code to > Python to change the application logic. I remember I wrote a Null > class that would behave as much as a "black whole" as possible. > It's in the O'Reilly Python Cookbook and available online here: > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 > > This might benefit from some more detailed inspection using ver- > sion 2.3 of Python, which I haven't done, yet. > > I might be possible to replace the current None (as currently con- > verted from nil) with a singleton Null instance, possibly as an > option only, if the code rewriting ever becomes more of a real > issue... I know that it can be very convenient in some cases if > "nothing" happens in a well-defined way! ;-) -1. It may be the ObjC way, but it's not the Python way. Remember we're using Python to use Cocoa and not to write ObjC with a nicer syntax... Just |
From: Dinu G. <gh...@da...> - 2003-05-06 16:11:36
|
Just van Rossum: > -1. It may be the ObjC way, but it's not the Python way. Remember = we're > using Python to use Cocoa and not to write ObjC with a nicer syntax... Well, let's not try to impose anybody's definition of what "pythonic" means to any group of people, like future Pythonistas coming from the Cocoa camp. In fact, I still haven't found a good definition of what it means to be "pythonic"... which is maybe good, because many great things lack a good, satisfactory definition. Saying something is pythonic, because it was in Python 0.x is probably not enough as we can see with Booleans, say, which were doomed to be evil until Python 2.2, or so. Wonderful-topic-for-a-discussion-fueled-by-Belgian-beer-;-)'ly, Dinu -- Dinu C. Gherman ...................................................................... "All you have to do is tell [the people] they are being attacked, and denounce the pacifists for lack of patriotism and exposing the country to danger. It works the same in any country." (Hermann=A0Goering, President of the Reichstag, 1932-45) |
From: Just v. R. <ju...@le...> - 2003-05-06 16:38:40
|
Dinu Gherman wrote: > Well, let's not try to impose anybody's definition of what "pythonic" > means to any group of people, like future Pythonistas coming from the > Cocoa camp. > > In fact, I still haven't found a good definition of what it means to > be "pythonic"... which is maybe good, because many great things lack > a good, satisfactory definition. Of course, there is no formal definition of "pythonic", there there is the list from "import this", the most well known (as well as abused) one is "Explicit is better than implicit". Also appripriate is In the face of ambiguity, refuse the temptation to guess. as well as Errors should never pass silently. > Saying something is pythonic, because it was in Python 0.x is probably > not enough as we can see with Booleans, say, which were doomed to be > evil until Python 2.2, or so. Sending messages to nil makes little sense in Python, as calling a method is always a two-step procedure: 1) get the bound method, 2) call the bound method. The fact that to emulate sending arbitrary messages to nil you need to create dummy bound method objects should (but apparently doesn't, to you ;-) clearly demonstrate that this does not fit the way Python _works_. IMO it has little to do with what is perceived to be Pythonic. > Wonderful-topic-for-a-discussion-fueled-by-Belgian-beer-;-)'ly, Sure thing ;-) Just |
From: Marcel W. <ma...@me...> - 2003-05-07 01:33:58
|
> > Of course, there is no formal definition of "pythonic", there there is > the list from "import this", the most well known (as well as abused) > one > is "Explicit is better than implicit". Not necessarily. For example, the polymorphism you get with OO is *implicit*. You didn't say which exact method you wanted, you just sent the message and let the system decide which specific implementation to use. And yes, there are still a number of people who consider this 'evil'. > Also appripriate is > > In the face of ambiguity, refuse the temptation to guess. Who is guessing? > as well as > > Errors should never pass silently. If they are actually errors in the first place... Marcel -- Marcel Weiher Metaobject Software Technologies ma...@me... www.metaobject.com Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc. |
From: Just v. R. <ju...@le...> - 2003-05-08 17:43:40
|
Marcel Weiher wrote: > > "Explicit is better than implicit". > > Not necessarily. For example, the polymorphism you get with OO is > *implicit*. You didn't say which exact method you wanted, you just > sent the message and let the system decide which specific > implementation to use. And yes, there are still a number of people > who consider this 'evil'. Bad example (I'm calling _this_ method on _that_ instance, I don't see what's implicit about that), but of course explicit isn't *always* better than implicit, it's merely a general guideline for how things work in Python (for example "12" + 13 raises an exception in Python, whereas Perl thinks "hey, this string looks like a number, lets treat it like that"). A _good_ counter example is Python's reference counting: it's implicit, yet better than manual ref counting. (To be completely explicit <wink>: in the context of Python at least.) Just |
From: Marcel W. <ma...@me...> - 2003-05-09 06:27:05
|
On Thursday, May 8, 2003, at 07:43 Uhr, Just van Rossum wrote: > Marcel Weiher wrote: > >>> "Explicit is better than implicit". >> >> Not necessarily. For example, the polymorphism you get with OO is >> *implicit*. You didn't say which exact method you wanted, you just >> sent the message and let the system decide which specific >> implementation to use. And yes, there are still a number of people >> who consider this 'evil'. > > Bad example (I'm calling _this_ method on _that_ instance, I don't see > what's implicit about that), Well, you aren't "calling" a "method" on an instance. You are sending a message to that instance, and that's not just a difference in wording, although getting the terminology right also generally helps. The message dispatch algorithm that is run implicitly each time you send a message (or do you see an explicit invocation of that algorithm?) tries to locate the method for the message sent, and it will search the superclass chain until it finds such a method, and even do something special (depending on the language) if it doesn't. Marcel -- Marcel Weiher Metaobject Software Technologies ma...@me... www.metaobject.com Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc. |
From: Just v. R. <ju...@le...> - 2003-05-09 07:48:56
|
Marcel Weiher wrote: > > Bad example (I'm calling _this_ method on _that_ instance, I don't > > see what's implicit about that), > > Well, you aren't "calling" a "method" on an instance. You are sending > a message to that instance, and that's not just a difference in > wording, although getting the terminology right also generally helps. That's just a matter of perspective. In Objective-C you call it "sending a message to an instance", in Python we call it "calling a method". The mechanics differ, but it's the same thing (OO with dynamic method dispatching). PyObjC demonstrates that clearly. However, the differences in the mechanics between Python and Objective-C make that "sending messages to nil" is a viable construct in Objective-C, but not in Python. (I agree with you there's some implicity involved in method calling, it's just that it doesn't feel that way to me since the rules are clearly defined.) Just |
From: Marcel W. <ma...@me...> - 2003-05-11 06:00:58
|
On Friday, May 9, 2003, at 09:48 Uhr, Just van Rossum wrote: > Marcel Weiher wrote: > >>> Bad example (I'm calling _this_ method on _that_ instance, I don't >>> see what's implicit about that), >> >> Well, you aren't "calling" a "method" on an instance. You are sending >> a message to that instance, and that's not just a difference in >> wording, although getting the terminology right also generally helps. > > That's just a matter of perspective. That turns out not to be the case. > In Objective-C you call it "sending > a message to an instance", in Python we call it "calling a method". Well, then you say it wrong "in Python". Seriously, there are other things you could call it, but "calling a method" is definitely not all that is happening. "Calling a method" would be correct if you already *had* the method and just invoked it. But that isn't what is happening: > The mechanics differ, but it's the same thing (OO with dynamic method > dispatching). Exactly. There is dynamic dispatch. So when you "send a message", you get dynamic dispatch, and THEN the method is called. If you just say "the method is called", you are simply *verbally* omitting the dynamic dispatch, though of course it is still happening. Of course, this just re-enforces my point that the dynamic dispatch of message sending is *implicit* in OO [it is being done, but it is not mentioned *explicitly* in the program code]. You seem to have even edited it out of your mental-model! ;-) > PyObjC demonstrates that clearly. Very clearly! > However, the differences in the mechanics between Python and > Objective-C > make that "sending messages to nil" is a viable construct in > Objective-C, but not in Python. > > (I agree with you there's some implicity involved in method calling, > it's just that it doesn't feel that way to me since the rules are > clearly defined.) Exactly my point, thank you! :-) The fact that it doesn't *feel* like that any longer for you just shows how implicit message sending (or dynamic dispatch, if you prefer) has become. So it goes with ignoring messages to nil: the rules are very clearly defined (a lot simpler than messages to other receivers), so there is no "general principle" that is being violated. It is just that you are used to something different, and haven't assimilated these particular rules (yet ;-). Regards, Marcel -- Marcel Weiher Metaobject Software Technologies ma...@me... www.metaobject.com Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc. |
From: Just v. R. <ju...@le...> - 2003-05-11 09:35:02
|
Marcel Weiher wrote: > > The mechanics differ, but it's the same thing (OO with dynamic > > method dispatching). > > Exactly. There is dynamic dispatch. So when you "send a message", > you get dynamic dispatch, and THEN the method is called. If you just > say "the method is called", you are simply *verbally* omitting the > dynamic dispatch, though of course it is still happening. That's just a matter of perspective <wink>: to me "the method foo of this object" means the method you'd get when dispatching. Since dynamic method dispatching is so deeply integrated in Python, I don't see how it could mean anything else, so I disagree I'm omitting something crucial. > > (I agree with you there's some implicity involved in method calling, > > it's just that it doesn't feel that way to me since the rules are > > clearly defined.) > > Exactly my point, thank you! :-) The fact that it doesn't *feel* > like that any longer for you just shows how implicit message sending > (or dynamic dispatch, if you prefer) has become. > > So it goes with ignoring messages to nil: the rules are very clearly > defined (a lot simpler than messages to other receivers), so there is > no "general principle" that is being violated. It is just that you > are used to something different, and haven't assimilated these > particular rules (yet ;-). I'm not arguing against sending messages to nil in ObjC (although I don't like it, see below), but against supporting it by PyObjC in *Python*. In ObjC it makes more sense since all dispatching goes through objc_msgSend(), so it can easily special-case nil. It simply doesn't work like that in Python, but I've explained that before (in case you missed it "bound method" is the key word). (Just yesterday I was working on some code where a (Cocoa) method unexpectedly returned nil (translated to None in Python). I was extremely happy to get a traceback instead of silent failure; since None is an actual object, it dispatches methods just like most other objects, ie. raise an exception if a method isn't found. A silent failure surely would've cost me much more time to figure out what I did wrong. Ignoring messages to nil is convenient when you expect it, but it's a liability when you don't. I much rather explicitly test for nil than shoot myself in the foot.) Just |
From: Ronald O. <ous...@ci...> - 2003-05-11 10:14:53
|
On Sunday, May 11, 2003, at 11:34 Europe/Amsterdam, Just van Rossum wrote: > (Just yesterday I was working on some code where a (Cocoa) method > unexpectedly returned nil (translated to None in Python). I was > extremely happy to get a traceback instead of silent failure; since > None > is an actual object, it dispatches methods just like most other > objects, > ie. raise an exception if a method isn't found. A silent failure surely > would've cost me much more time to figure out what I did wrong. > Ignoring > messages to nil is convenient when you expect it, but it's a liability > when you don't. I much rather explicitly test for nil than shoot myself > in the foot.) This is the most important reason for not having a 'nil' object that behaves ignores all method calls. Implementing such an object is easy enough, but it is too easy to mis actual errors this way. And IIRC this feature doesn't even work perfectly in Objective-C (what if the method returns anything other than an 'id', like a float/double/struct). Ronald |
From: <bb...@ma...> - 2003-05-11 13:52:55
|
On Sunday, May 11, 2003, at 05:46 US/Eastern, Ronald Oussoren wrote: > This is the most important reason for not having a 'nil' object that > behaves ignores all method calls. Implementing such an object is easy > enough, but it is too easy to mis actual errors this way. And IIRC > this feature doesn't even work perfectly in Objective-C (what if the > method returns anything other than an 'id', like a > float/double/struct). Having done ObjC development since 1989 -- 4 or 5 years prior to diving into Python -- you might be surprised to learn that I very strongly prefer the behavior of Python's (and Java's) 'message to nil throws' behavior vs. ObjC's 'message to nil silently eaten'. When everything is working correctly 'message to nil silently eaten' is a great convenience. When something somewhere unexpectedly returns nil, it becomes an incredibly nasty pain to try and figure out exactly where the problem might be. By the time it crops up, you may be many cycles through the run loop away from where the problem actually is. Over the last-- jeez, nearly 15 years-- I have seen novice and experienced developers-- myself included-- waste many many hours trying to track down a problem that turned out to be an unexpected nil. Going with a 'message to nil raises' model may have required the addition of quite a few extra if () statements here and there over the years, but that route would have considerably decreased the frustration factor for quite a large number of developers. Even though objc_msgSend() supports the other dispatch model, you can't mix and match within a single application for obvious reasons. In the context of PyObjC, I consider 'message to nil throws' to be a feature (and not just because it is the Python way). b.bum |
From: Dinu G. <gh...@da...> - 2003-05-11 14:41:20
|
bb...@ma...: > Over the last-- jeez, nearly 15 years-- I have seen novice and > experienced developers-- myself included-- waste many many hours > trying to track down a problem that turned out to be an unexpected > nil. Going with a 'message to nil raises' model may have required > the addition of quite a few extra if () statements here and there over > the years, but that route would have considerably decreased the > frustration factor for quite a large number of developers. While one can surely argue about the value of "messages to nil being eaten or not", I think all OO purists will agree that checking for the type of an object (which here includes: comparing to nil/None) is a very bad idea! You save lots of if-statements if you can dele- gate your decission-making to the message dispatching mechanism. Nil is just another singleton value to compare with (like null poin- ters in C). So, sometimes it might just suffice for it to "eat your messages", but to obtain clean code you more often want to have a single but special value of some class which behaves differently in *some* respect (leaves in trees, etc.). This is where the "Null" pattern comes in, because you can also use it as a subclass of your "real" representation (class). See my original link for further info. If you use a Null object that way you won't have the kind of trouble that you and Just are citing, because you have only "regular" objects and (mostly) one special case object. I guess, the creators of ObjC just were trying to help people using nil like this. But as I said, it won't always be enough to "eat everything." Regards, Dinu -- Dinu C. Gherman ...................................................................... "I want to put a ding in the universe." (Steve Jobs) |
From: Martina O. <Ma...@Oe...> - 2003-05-11 15:49:16
|
Hi Bill - > When everything is working correctly 'message to nil silently eaten' > is a great convenience. When something somewhere unexpectedly returns > nil, it becomes an incredibly nasty pain to try and figure out exactly > where the problem might be. By the time it crops up, you may be many > cycles through the run loop away from where the problem actually is. Agreed. > In the context of PyObjC, I consider 'message to nil throws' to be a > feature (and not just because it is the Python way). Unfortunately Cocoa uses the "message to nil ignored" pattern without documenting it. For example, the AddressBook methods which return arrays of people, groups etc. may return nil instead of an NSArray. As these details are not mentioned in Apple's documentation, they are a trap for PyObjc programmers. One way to fix this might be to translate Cocoa's nil to Dinu's Null class. But this might break existing programs which now compare Cocoa return values to None. Also there might be round-trip problems (what happens if you stored a Python None in an NSMutableArray. When you retrieve it later, will you get None or a Null object?). Probably there will be more problems of this kind, similar to what we have seen with other conversions in the bridge. Therefore I prefer the existing behaviour. However, I suggest to document it more detailed than now (list known examples of Cocoa returning a "to be ignored" nil), and to add explicit tests for nil to the example and tests where appropriate. ciao Martina |
From: Marcel W. <ma...@me...> - 2003-05-11 15:49:22
|
On Sunday, May 11, 2003, at 03:49 Uhr, bb...@ma... wrote: > On Sunday, May 11, 2003, at 05:46 US/Eastern, Ronald Oussoren wrote: >> This is the most important reason for not having a 'nil' object that >> behaves ignores all method calls. Implementing such an object is easy >> enough, but it is too easy to mis actual errors this way. And IIRC >> this feature doesn't even work perfectly in Objective-C (what if the >> method returns anything other than an 'id', like a >> float/double/struct). > > Having done ObjC development since 1989 -- 4 or 5 years prior to > diving into Python -- you might be surprised to learn that I very > strongly prefer the behavior of Python's (and Java's) 'message to nil > throws' behavior vs. ObjC's 'message to nil silently eaten'. Having done ObjC development since 1987, I much prefer the coding simplicity the current behavior gives, while I don't recall the problems you report being anything but an extremely rare occurrence. > When everything is working correctly 'message to nil silently eaten' > is a great convenience. When something somewhere unexpectedly returns > nil, it becomes an incredibly nasty pain to try and figure out exactly > where the problem might be. By the time it crops up, you may be many > cycles through the run loop away from where the problem actually is. Hmmm...this sounds like you are working too much with mutable state, in which case nils are just one symptom, and doctoring about with this one symptom is just hiding the deeper problems. If you move away from mutable state, you will also find that you don't have problematic values (of which nil is just one prominent example) causing problems when the cause of the problem (of the problematic value) has long since disappeared from the call-stack. If you use a more "functional" programming style, pulling values and evaluating expressions when needed instead of pushing values and stashing computed values, you will likely find that you don't get this type of problem-propagation. > Over the last-- jeez, nearly 15 years-- I have seen novice and > experienced developers-- myself included-- waste many many hours > trying to track down a problem that turned out to be an unexpected > nil. Going with a 'message to nil raises' model may have required > the addition of quite a few extra if () statements here and there over > the years, but that route would have considerably decreased the > frustration factor for quite a large number of developers. While I don't question your personal experience, I do believe that the problem may lie elsewhere. Also, I believe very strongly in "intention-revealing" code. That is, the code should reflect the problem, not the technology. Things like constant checking of types/nil-values/exceptions typically have nothing to do with the problem domain, and do little but obscure the solution. I certainly notice that my Java code is a lot more verbose and a lot less maintainable than my Objective-C code. Marcel -- Marcel Weiher Metaobject Software Technologies ma...@me... www.metaobject.com Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc. |
From: <bb...@ma...> - 2003-05-11 21:20:14
|
On Sunday, May 11, 2003, at 11:49 US/Eastern, Marcel Weiher wrote: >> Having done ObjC development since 1989 -- 4 or 5 years prior to >> diving into Python -- you might be surprised to learn that I very >> strongly prefer the behavior of Python's (and Java's) 'message to nil >> throws' behavior vs. ObjC's 'message to nil silently eaten'. > > Having done ObjC development since 1987, I much prefer the coding > simplicity the current behavior gives, while I don't recall the > problems you report being anything but an extremely rare occurrence. Difference in experience then -- I have spent a good part of my career mentoring teams to help them achieve success. This is typically done in environments where the project is under "schedule stress". More often than not a major source of stress is "strange or intermittent failures". If you have a construct like... [[[[foo bar] baz] bob] fred]; ... and any one of -bar, -baz, -bob, or -fred unexpectedly returns nil when it shouldn't, debugging is a nightmare. >> When everything is working correctly 'message to nil silently eaten' >> is a great convenience. When something somewhere unexpectedly >> returns nil, it becomes an incredibly nasty pain to try and figure >> out exactly where the problem might be. By the time it crops up, >> you may be many cycles through the run loop away from where the >> problem actually is. > > Hmmm...this sounds like you are working too much with mutable state, > in which case nils are just one symptom, and doctoring about with this > one symptom is just hiding the deeper problems. If you move away from > mutable state, you will also find that you don't have problematic > values (of which nil is just one prominent example) causing problems > when the cause of the problem (of the problematic value) has long > since disappeared from the call-stack. > > If you use a more "functional" programming style, pulling values and > evaluating expressions when needed instead of pushing values and > stashing computed values, you will likely find that you don't get this > type of problem-propagation. No -- that is not the problem. There is the potential for the problem to arise *anywhere* a method is invoked/called/messaged where the developer has not previously validated that the target is non-nil. If, for whatever, reason-- misconnection in IB, service mysteriously down, data integrity damage-- the target is nil, no error will occur upon method invocation and the fact that said object reference was nil will now cause a problem that may be considerably separated from the actual source of the problem. >> Over the last-- jeez, nearly 15 years-- I have seen novice and >> experienced developers-- myself included-- waste many many hours >> trying to track down a problem that turned out to be an unexpected >> nil. Going with a 'message to nil raises' model may have required >> the addition of quite a few extra if () statements here and there >> over the years, but that route would have considerably decreased the >> frustration factor for quite a large number of developers. > > While I don't question your personal experience, I do believe that the > problem may lie elsewhere. > > Also, I believe very strongly in "intention-revealing" code. That is, > the code should reflect the problem, not the technology. Things like > constant checking of types/nil-values/exceptions typically have > nothing to do with the problem domain, and do little but obscure the > solution. I certainly notice that my Java code is a lot more verbose > and a lot less maintainable than my Objective-C code. It would seem that "intention revealing" would mean writing code that shows that the developer intended to deal with the fact that something could potentially be nil in a valid situation by actually checking for it. [[[[foo bar] baz] bob] fred]; The above does not reveal the developers intentions in this regard -- maybe the developer fully expects -baz and -fred to return nil and that's OK -- but -bar and -bob returning nil is something the developer never intended to have happen. If an exception were thrown in such a case, the above would change to: id x; x = [[foo bar] baz]; if (!x) return; x = [[x bob] fred]; if (!x) return; The above is a few more lines of code, but the developer's intentions are exactly revealed. b.bum |
From: Marcel W. <ma...@me...> - 2003-05-11 22:23:30
|
On Sunday, May 11, 2003, at 11:20 Uhr, bb...@ma... wrote: > On Sunday, May 11, 2003, at 11:49 US/Eastern, Marcel Weiher wrote: >>> Having done ObjC development since 1989 -- 4 or 5 years prior to >>> diving into Python -- you might be surprised to learn that I very >>> strongly prefer the behavior of Python's (and Java's) 'message to >>> nil throws' behavior vs. ObjC's 'message to nil silently eaten'. >> >> Having done ObjC development since 1987, I much prefer the coding >> simplicity the current behavior gives, while I don't recall the >> problems you report being anything but an extremely rare occurrence. > > Difference in experience then -- Obviously. It begs the question: why are you experiencing these problems? It can't really be message-eating nil by itself, because then I should be experiencing those same problems. But I am not. > I have spent a good part of my career mentoring teams to help them > achieve success. Good for you! Maybe that is why you are experiencing those problems and I do not, because you help with success and I only help with failure... > This is typically done in environments where the project is under > "schedule stress". More often than not a major source of stress is > "strange or intermittent failures". Lucky you! I only wish my major sources of stress were something I had control over. My sources of "stress" are usually somewhat more external, like a customer whose customer is about to pull the plug on them because their 3rd attempt at delivering a content management system also failed, and now they've come to us and we have 3 days to get the system running when we had planned for another couple of months. With the added stress that my master's thesis for university is due that same week (that was fun!) Or arriving at a trade show to find that the equipment you've been provided doesn't actually work, and you have to re-write the RIP software for tomorrow morning...well, actually for later today...things like that. > If you have a construct like... > > [[[[foo bar] baz] bob] fred]; > > ... and any one of -bar, -baz, -bob, or -fred unexpectedly returns nil > when it shouldn't, debugging is a nightmare. Really? Actually, debugging such deeply nested expressions with gdb really is a pain, but this also has nothing to do with nil-eating or not nil-eating. It has to do with deeply nested expressions and the difficulty of setting breakpoints within such an expression. >>> When everything is working correctly 'message to nil silently eaten' >>> is a great convenience. When something somewhere unexpectedly >>> returns nil, it becomes an incredibly nasty pain to try and figure >>> out exactly where the problem might be. By the time it crops up, >>> you may be many cycles through the run loop away from where the >>> problem actually is. >> >> Hmmm...this sounds like you are working too much with mutable state, >> in which case nils are just one symptom, and doctoring about with >> this one symptom is just hiding the deeper problems. If you move >> away from mutable state, you will also find that you don't have >> problematic values (of which nil is just one prominent example) >> causing problems when the cause of the problem (of the problematic >> value) has long since disappeared from the call-stack. >> >> If you use a more "functional" programming style, pulling values and >> evaluating expressions when needed instead of pushing values and >> stashing computed values, you will likely find that you don't get >> this type of problem-propagation. > > No -- that is not the problem. Objection: if you are "...many cycles through the run loop away..." then you are *definitely* having a problem with propagating incorrect values in mutable state. Unless you have found a magical method of keeping temporary variables around between event-loop cycles (cyrogenics? ;-) > There is the potential for the problem to arise *anywhere* a method is > invoked/called/messaged where the developer has not previously > validated that the target is non-nil. Well, otherwise it is even worse. You have the chance of an exception messing you up despite the fact that there may not actually be a problem. For example, to be safe, the simple line of code above would have to check for nil before every message send: [[[[foo bar] baz] bob] fred]; if ( foo!=nil ) { id temp1=[foo bar]; if ( temp1 != nil ) { [temp1 baz]; ... and so on ... } } Why? Well, if nil is a problem in the code-snippet, then it is obviously unexpected. Otherwise, it would either be handled or ignoring it would be OK. However, if it is unexpected, then you can't say which message-send will return nil "unexpectedly"... [snip] >> Also, I believe very strongly in "intention-revealing" code. That >> is, the code should reflect the problem, not the technology. Things >> like constant checking of types/nil-values/exceptions typically have >> nothing to do with the problem domain, and do little but obscure the >> solution. I certainly notice that my Java code is a lot more verbose >> and a lot less maintainable than my Objective-C code. > > It would seem that "intention revealing" would mean writing code that > shows that the developer intended to deal with the fact that something > could potentially be nil in a valid situation by actually checking for > it. That turns out not to be the case. "Intention revealing" means that you reveal what the *intent* of the code is. Error-handling is *implementation*, because I am sure it is not your intention to cause errors...well, I *hope* it isn't ;-) [snip] Anyway, I am fairly confident that this discussion has outlived its usefulness. I have no problem with you preferring "raising-nil" if that helps you and your colleagues/clients. I just want to point out that the problems you seem to have experienced are not universally shared, and it is therefore quite reasonable to come to different conclusions. Marcel -- Marcel Weiher Metaobject Software Technologies ma...@me... www.metaobject.com Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc. |
From: Marcel W. <ma...@me...> - 2003-05-11 15:30:55
|
On Sunday, May 11, 2003, at 11:34 Uhr, Just van Rossum wrote: > Marcel Weiher wrote: > >>> The mechanics differ, but it's the same thing (OO with dynamic >>> method dispatching). >> >> Exactly. There is dynamic dispatch. So when you "send a message", >> you get dynamic dispatch, and THEN the method is called. If you just >> say "the method is called", you are simply *verbally* omitting the >> dynamic dispatch, though of course it is still happening. > > That's just a matter of perspective <wink>: to me "the method foo of > this object" means the method you'd get when dispatching. Yes. This means that you have *implied* a dispatching mechanism when you speak of "the method foo of this object". (You didn't mention it explicitly, but it is there -> implied). What about this is difficult? > Since dynamic > method dispatching is so deeply integrated in Python, I don't see how > it > could mean anything else, so I disagree I'm omitting something crucial. I am not saying that you are "omitting" anything. I am saying you are not mentioning *explicitly*, but *implicitly*. This behavior is implied by what you are saying. > I'm not arguing against sending messages to nil in ObjC (although I > don't like it, see below), but against supporting it by PyObjC in > *Python*. I have no problem with handling it one way or the other. I had a problem with the 'reasoning' you presented, which was quite wrong. > (Just yesterday I was working on some code where a (Cocoa) method > unexpectedly returned nil (translated to None in Python). I was > extremely happy to get a traceback instead of silent failure; since > None > is an actual object, it dispatches methods just like most other > objects, > ie. raise an exception if a method isn't found. A silent failure surely > would've cost me much more time to figure out what I did wrong. > Ignoring > messages to nil is convenient when you expect it, but it's a liability > when you don't. I much rather explicitly test for nil than shoot myself > in the foot.) Well, I am just as happy that I don't have to obscure my code with clutter... So there we are, two happy people ;-) Marcel -- Marcel Weiher Metaobject Software Technologies ma...@me... www.metaobject.com Metaprogramming for the Graphic Arts. HOM, IDEAs, MetaAd etc. |