uhb*_*f19 5 debugging smalltalk pharo
当您启动代码发送未实现的消息时,Pharo启动调试器.
据我所知,它通过Object >> doesNotUnderstand,触发异常,这导致调试器窗口.
问题是究竟做了Object >> doesNotUnderstand什么,以及与其他交互式帮助者有什么不同,比如从不存在的变量开始?
小智 6
调试器将作为对未处理异常的响应而打开.为了更好地解释,我们可以从触发系统中未捕获的异常开始.例如,我们可以在Playground中执行Error signal: 'an error'.(信号在Pharo中抛出错误).这将打开以下调试器:
发生异常时,系统首先尝试为该异常查找异常处理程序.如果未找到异常处理程序,则系统将消息发送defaultAction到异常.这在类中实现Error为:
Error>>#defaultAction
"No one has handled this error, but now give them a chance to decide how
to debug it. If none handle this either then open debugger
(see UnhandedError-defaultAction)"
UnhandledError signalForException: self
Run Code Online (Sandbox Code Playgroud)
因此,系统通过抛出另一个异常来响应未处理的异常UnhandledError.同样,如果没有为新异常找到异常处理程序,系统会将消息发送defaultAction到异常对象.在这种情况下,异常是一个实例,UnhandledError并且此类覆盖defaultAction具有以下实现:
UnhandledError>>#defaultAction
<reflective: #unhandledErrorDefaultAction:message:>
^ UIManager default unhandledErrorDefaultAction: self exception
Run Code Online (Sandbox Code Playgroud)
该方法unhandledErrorDefaultAction:非常简单,只是向异常对象发送消息debug.
MorphicUIManager>>#unhandledErrorDefaultAction: anException
anException debug
Run Code Online (Sandbox Code Playgroud)
方法debug Exception在Pharo中的所有异常的根类中实现为:
Exception>>#debug
"open a debugger on myself"
Processor activeProcess
debug: self signalerContext
title: self description
Run Code Online (Sandbox Code Playgroud)
这就是打开调试器的原因.
在向对象发送未知消息的情况下MessageNotUnderstood,该方法抛出类型异常Object>>#doesNotUnderstand:.此异常遵循与之前相同的链,系统最终将debug消息发送到MessageNotUnderstood打开调试器的异常.
简而言之:
#doesNotUnderstand:;doesNotUnderstand:提出类型的例外MessageNotUnderstood;UnhandledError;UnhandledError没有捕获到它,它会要求UI管理器处理这种情况;debug到初始异常,在这种情况下是MessageNotUnderstood异常(仅MorphicUIManager执行此操作;其他UI管理器喜欢CommandLineUIManager执行其他操作,如现有映像);debug消息打开调试器不存在的变量的处理程序具有与实际编译器完全不同的实现.当代码在具有未知变量的类中编译时,编译器会检测到该代码并询问用户要执行的操作:创建新的实例变量或本地参数.
如果您尝试执行包含未知类的代码,UnnknowsClass new.则编译器也会检测到此类并询问用户该怎么做.在这种情况下没有例外.
还有其他帮助程序使用相同的机制doesNotUnderstand:,例如引发通知.如果执行Object new notify: 'a notification'该方法,则notify:抛出Warning异常,最终打开调试器.
为了补充Adrei Chis给出的优秀答案,让我补充一点,该消息#doesNotUnderstad:与其他消息略有不同.
每次发送消息时,运行时(通常在虚拟机中)都会找到与正在发送的消息的选择器的预期接收者相对应的方法.
它通过查看接收者的行为来做到这一点.如果没有找到方法,则转到继承的行为(通常是超类中定义的行为),并继续这种方式,直到找到方法或继承链耗尽为止.此搜索称为方法查找.
在第二种情况下(当对象的行为层次结构中不存在任何方法时),Runtime(1)通过创建一个Message未找到选择器的对象和实际参数(如果有的话)和(2)发送接收器来重新启动消息带有选择器#doesNotUnderstand:和参数的新消息刚才具有的消息.
查找过程重复,并且(很可能)这次#doesNotUnderstand:为接收器找到了选择 器(可能已经实现了自己的版本,或者从类层次结构的顶部继承了它).此时,Adrei描述的步骤如下.
如果由于任何原因接收器不理解#doesNotUnderstand:(双关语),运行时无法继续并关闭系统(它还能做什么?)
另请注意,如果发送消息,查找会略有不同super.但这是另一个故事,而这个问题的基本思想仍然存在.