当消息不被理解时,Pharo 如何启动调试器?
How does Pharo starts debugger when message is not understanded?
当您开始发送未实现消息的代码时,Pharo 会启动调试器。
据我所知,它通过 Object >> doesNotUnderstand
工作,这会触发异常,这会导致调试器 window。
问题是 Object >> doesNotUnderstand
到底做了什么,它与其他交互式助手有何不同,比如从不存在的变量开始?
调试器作为对未处理异常的响应而打开。为了更好地解释,我们可以从触发系统中任何地方都没有捕获到的异常开始。例如,我们可以在 Playground Error signal: 'an error'.
中执行(信号在 Pharo 中抛出错误)。这将打开以下调试器:
当异常发生时,系统首先尝试为该异常寻找异常处理程序。如果未找到异常处理程序,则系统将消息 defaultAction
发送到异常。这在 class 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
因此系统通过抛出另一个异常来响应未处理的异常,UnhandledError
。同样,如果没有为新异常找到异常处理程序,系统将消息 defaultAction
发送到异常对象。在这种情况下,异常是 UnhandledError
的一个实例,并且此 class 重写器 defaultAction
具有以下实现:
UnhandledError>>#defaultAction
<reflective: #unhandledErrorDefaultAction:message:>
^ UIManager default unhandledErrorDefaultAction: self exception
方法unhandledErrorDefaultAction:
非常简单,只是向异常对象发送消息debug
。
MorphicUIManager>>#unhandledErrorDefaultAction: anException
anException debug
方法调试在Exception
中实现,Pharo中所有异常的根源class为:
Exception>>#debug
"open a debugger on myself"
Processor activeProcess
debug: self signalerContext
title: self description
这就是打开调试器的原因。
在向对象发送未知消息的情况下,方法 Object>>#doesNotUnderstand:
会抛出类型 MessageNotUnderstood
的异常。此异常遵循与以前相同的链,系统最终将 debug
消息发送到打开调试器的 MessageNotUnderstood
异常。
简而言之:
- 当向对象发送未知消息时,系统会向该对象发送消息
#doesNotUnderstand:
;
doesNotUnderstand:
引发 MessageNotUnderstood
; 类型的异常
- 如果未捕获此异常,则会引发另一个
UnhandledError
类型的异常;
- 如果这个新的
UnhandledError
没有被抓到,它会要求 UI 经理处理这个案例;
- UI 管理器将消息
debug
发送到初始异常,在本例中为 MessageNotUnderstood
异常(只有 MorphicUIManager
这样做;其他 UI 像 CommandLineUIManager
这样的经理会执行其他操作,例如现有图像);
debug
消息打开调试器
不存在变量的处理程序与实际编译器中的实现完全不同。当代码在具有未知变量的 class 中编译时,编译器会检测到并询问用户该怎么做:创建一个新的实例变量或局部参数。
如果您尝试执行包含未知 class 的代码,例如 UnnknowsClass new.
,编译器也会检测到这一点并询问用户该怎么做。在这种情况下没有引发异常。
还有其他助手使用与 doesNotUnderstand:
相同的机制,例如发出通知。如果你执行 Object new notify: 'a notification'
方法 notify:
抛出一个 Warning
异常,最终打开调试器。
为了补充 Adrei Chis 给出的出色答案,让我补充一下消息 #doesNotUnderstad:
与其他消息略有不同。
每次发送消息时,运行时(通常在虚拟机中)都会为正在发送的消息的选择器找到与预期接收者相对应的方法。
它通过查看接收者的行为来做到这一点。如果没有找到方法,它会转到继承行为(通常是在 superclass 中定义的行为),并继续这种方式直到找到方法或继承链耗尽。此搜索称为 方法查找 。
在第二种情况下(当对象的行为层次结构中不存在任何方法时),运行时 (1) 通过创建 Message
未找到选择器的对象和实际参数 (如果有的话)和(2)向接收者发送一条带有选择器 #doesNotUnderstand:
的新消息,并且参数是刚刚具体化的消息。
重复查找过程,并且(很可能)这次为接收者找到了选择器 #doesNotUnderstand:
(它可能已经实现了自己的版本,或者从 [=33 的顶部继承了它=] 层次结构)。此时将执行 Adrei 描述的步骤。
如果出于任何原因接收者不理解#doesNotUnderstand:
(双关语),运行时将无法继续并关闭系统(它还能做什么?)
另请注意,如果消息发送至 super
,查找会略有不同。但那是另一个故事和基本思想 w.r.t。这个问题仍然存在。
当您开始发送未实现消息的代码时,Pharo 会启动调试器。
据我所知,它通过 Object >> doesNotUnderstand
工作,这会触发异常,这会导致调试器 window。
问题是 Object >> doesNotUnderstand
到底做了什么,它与其他交互式助手有何不同,比如从不存在的变量开始?
调试器作为对未处理异常的响应而打开。为了更好地解释,我们可以从触发系统中任何地方都没有捕获到的异常开始。例如,我们可以在 Playground Error signal: 'an error'.
中执行(信号在 Pharo 中抛出错误)。这将打开以下调试器:
当异常发生时,系统首先尝试为该异常寻找异常处理程序。如果未找到异常处理程序,则系统将消息 defaultAction
发送到异常。这在 class 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
因此系统通过抛出另一个异常来响应未处理的异常,UnhandledError
。同样,如果没有为新异常找到异常处理程序,系统将消息 defaultAction
发送到异常对象。在这种情况下,异常是 UnhandledError
的一个实例,并且此 class 重写器 defaultAction
具有以下实现:
UnhandledError>>#defaultAction
<reflective: #unhandledErrorDefaultAction:message:>
^ UIManager default unhandledErrorDefaultAction: self exception
方法unhandledErrorDefaultAction:
非常简单,只是向异常对象发送消息debug
。
MorphicUIManager>>#unhandledErrorDefaultAction: anException
anException debug
方法调试在Exception
中实现,Pharo中所有异常的根源class为:
Exception>>#debug
"open a debugger on myself"
Processor activeProcess
debug: self signalerContext
title: self description
这就是打开调试器的原因。
在向对象发送未知消息的情况下,方法 Object>>#doesNotUnderstand:
会抛出类型 MessageNotUnderstood
的异常。此异常遵循与以前相同的链,系统最终将 debug
消息发送到打开调试器的 MessageNotUnderstood
异常。
简而言之:
- 当向对象发送未知消息时,系统会向该对象发送消息
#doesNotUnderstand:
; doesNotUnderstand:
引发MessageNotUnderstood
; 类型的异常
- 如果未捕获此异常,则会引发另一个
UnhandledError
类型的异常; - 如果这个新的
UnhandledError
没有被抓到,它会要求 UI 经理处理这个案例; - UI 管理器将消息
debug
发送到初始异常,在本例中为MessageNotUnderstood
异常(只有MorphicUIManager
这样做;其他 UI 像CommandLineUIManager
这样的经理会执行其他操作,例如现有图像); debug
消息打开调试器
不存在变量的处理程序与实际编译器中的实现完全不同。当代码在具有未知变量的 class 中编译时,编译器会检测到并询问用户该怎么做:创建一个新的实例变量或局部参数。
如果您尝试执行包含未知 class 的代码,例如 UnnknowsClass new.
,编译器也会检测到这一点并询问用户该怎么做。在这种情况下没有引发异常。
还有其他助手使用与 doesNotUnderstand:
相同的机制,例如发出通知。如果你执行 Object new notify: 'a notification'
方法 notify:
抛出一个 Warning
异常,最终打开调试器。
为了补充 Adrei Chis 给出的出色答案,让我补充一下消息 #doesNotUnderstad:
与其他消息略有不同。
每次发送消息时,运行时(通常在虚拟机中)都会为正在发送的消息的选择器找到与预期接收者相对应的方法。
它通过查看接收者的行为来做到这一点。如果没有找到方法,它会转到继承行为(通常是在 superclass 中定义的行为),并继续这种方式直到找到方法或继承链耗尽。此搜索称为 方法查找 。
在第二种情况下(当对象的行为层次结构中不存在任何方法时),运行时 (1) 通过创建 Message
未找到选择器的对象和实际参数 (如果有的话)和(2)向接收者发送一条带有选择器 #doesNotUnderstand:
的新消息,并且参数是刚刚具体化的消息。
重复查找过程,并且(很可能)这次为接收者找到了选择器 #doesNotUnderstand:
(它可能已经实现了自己的版本,或者从 [=33 的顶部继承了它=] 层次结构)。此时将执行 Adrei 描述的步骤。
如果出于任何原因接收者不理解#doesNotUnderstand:
(双关语),运行时将无法继续并关闭系统(它还能做什么?)
另请注意,如果消息发送至 super
,查找会略有不同。但那是另一个故事和基本思想 w.r.t。这个问题仍然存在。