Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
Best, Marcel Am 12.06.2023 14:23:53 schrieb Thiede, Christoph christoph.thiede@student.hpi.uni-potsdam.de: Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best, Christoph
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph christoph.thiede@student.hpi.uni-potsdam.de:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
________________________________ Von: Tobias Pape Das.Linux@gmx.de Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph christoph.thiede@student.hpi.uni-potsdam.de:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi
On 12. Jun 2023, at 16:09, Thiede, Christoph Christoph.Thiede@student.hpi.uni-potsdam.de wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething] on: self class applicationErrors do: [...] [self doSomethingElse] on: self class applicationErrors , self class systemErrors do: [...]
Yeah, please do not do that. except in very select circumstances, these Exception classes should be literal there.
and on the class side:
class>>applicationErrors ^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors ^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors,
Which is on the meta-level for the Exception-handling-infrastructure.
and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
If your bottleneck is in that kind of area, I shall be very surprised. And if so, maybe the error checking is on a too low level?
Anyway, handling more than one exception case at once should probably a rare occasion.
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
So? Let it be inefficiently degenerated :)
Don't fix it if it is not broken.
Best regards -Tobias
Best, Christoph Von: Tobias Pape Das.Linux@gmx.de Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph christoph.thiede@student.hpi.uni-potsdam.de:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph < Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure
, MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet
ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult
class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
*Von:* Tobias Pape Das.Linux@gmx.de *Gesendet:* Montag, 12. Juni 2023 15:54:46 *An:* The general-purpose Squeak developers list *Betreff:* [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <
squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for
copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <
christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument
exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering
a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it
idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
Cheers, Patrick
________________________________________ From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet
ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
________________________________ Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
-- _,,,^..^,,,_ best, Eliot
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that.
except in very select circumstances, these Exception classes should be literal there.
Why? Just because it relieves us of the burden of worrying about copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
Is it because of performance? That would surprise me, because Tobias just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
Is it because of intuition? I can't imagine that. As Patrick said, #, is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
Is it because you are afraid that the change might break something? Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
Eliot suggests that we could provide an immutable #+ on ExceptionSet instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] [cid:c462a563-d939-4b70-bfce-7dff87dc1b86]
**) 10 timesRepeat: [Smalltalk garbageCollect]. [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC time.' NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC time.'
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors) [cid:80aa495a-0611-4ce6-becf-2ecd91142f76]
________________________________ Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi
On 15. Jun 2023, at 20:03, Thiede, Christoph Christoph.Thiede@student.hpi.uni-potsdam.de wrote:
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that. except in very select circumstances, these Exception classes should be literal there.
Why? Just because it relieves us of the burden of worrying about copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
no.
Is it because of performance? That would surprise me, because Tobias just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
no.
Is it because of intuition? I can't imagine that. As Patrick said, #, is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
no.
Is it because you are afraid that the change might break something? Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
no.
It is because the exceptions caught should never be hidden behind a variable or sent
This one sparks joy:
[] on: MyApplicationFailure , MyApplicationPanic do: [self barf]
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
Eliot suggests that we could provide an immutable #+ on ExceptionSet instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
In python, you need language to do
try: break() except MyApplicationFailure, MyApplicationPanic as e: barf()
we can just use messages. The #, on Exception and ExceptionSet are just a bit of niceness to make things look good. There is no point in seeing them like "proper collections".
If I could, I'd raise an error when #, is sent to a non-literally constructed ExceptionSet ;P
:D
Best regards -Tobias
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] <pastedImage.png>
**) 10 timesRepeat: [Smalltalk garbageCollect]. [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC time.' NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC time.'
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors) <pastedImage.png>
Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Ah, and so implementing #, with crude semantics is your way of punishing programmers who do not follow your idea of clean exception handling code? :P
But if we really want to discuss that:
It is because the exceptions caught should never be hidden behind a variable or sent
Disagree!
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
This is not the example I would like to talk about. :-) Let's talk about this one instead:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
I do prefer this very much to duplicating and leaking the specific exception classes which are not relevant in this place. Plus, we should not artificially limit the capabilities of metaprogramming. Even though situations where some things might be rare, they always exist ... There are situations where accessing variables through #instVarNamed: makes sense. There are situations where using #ifTrue: in a cascade is helpful. There are situations where using thisContext from a return can be practical. I see no sense in Smalltalk to disallow such patterns rather than to disrecommend them ...
Best, Christoph
________________________________ Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 20:58:35 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
Hi
On 15. Jun 2023, at 20:03, Thiede, Christoph Christoph.Thiede@student.hpi.uni-potsdam.de wrote:
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that. except in very select circumstances, these Exception classes should be literal there.
Why? Just because it relieves us of the burden of worrying about copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
no.
Is it because of performance? That would surprise me, because Tobias just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
no.
Is it because of intuition? I can't imagine that. As Patrick said, #, is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
no.
Is it because you are afraid that the change might break something? Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
no.
It is because the exceptions caught should never be hidden behind a variable or sent
This one sparks joy:
[] on: MyApplicationFailure , MyApplicationPanic do: [self barf]
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
Eliot suggests that we could provide an immutable #+ on ExceptionSet instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
In python, you need language to do
try: break() except MyApplicationFailure, MyApplicationPanic as e: barf()
we can just use messages. The #, on Exception and ExceptionSet are just a bit of niceness to make things look good. There is no point in seeing them like "proper collections".
If I could, I'd raise an error when #, is sent to a non-literally constructed ExceptionSet ;P
:D
Best regards -Tobias
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] <pastedImage.png>
**) 10 timesRepeat: [Smalltalk garbageCollect]. [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC time.' NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC time.'
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors) <pastedImage.png>
Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi
On 15. Jun 2023, at 21:47, Thiede, Christoph Christoph.Thiede@student.hpi.uni-potsdam.de wrote:
Ah, and so implementing #, with crude semantics is your way of punishing programmers who do not follow your idea of clean exception handling code? :P
No. I say the "correct" semantics have no place to be used.
But if we really want to discuss that:
It is because the exceptions caught should never be hidden behind a variable or sent
Disagree!
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
This is not the example I would like to talk about. :-) Let's talk about this one instead:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
I do prefer this very much to duplicating and leaking the specific exception classes which are not relevant in this place.
I really do not like that style. Other languages would barf on this kind of thing and rightfully so! encapsulation is good, yes, abstraction as well. But this is just hiding stuff for no good reason.
If you need to handle multiple kinds of exceptions, thats already problematic. if you need to do it multiple times in the same method, I'd say there's an architectural problem to begin with.
Plus, we should not artificially limit the capabilities of metaprogramming. Even though situations where some things might be rare, they always exist ... There are situations where accessing variables through #instVarNamed: makes sense. There are situations where using #ifTrue: in a cascade is helpful. There are situations where using thisContext from a return can be practical. I see no sense in Smalltalk to disallow such patterns rather than to disrecommend them ...
Come on, that's a straw man :(
So, the runtime does not really care where the Object that represent the exception come from. But readers should.
I'd say: - If possible, handle one kind of exception at once:
[] on: MyException do: [:e | self foo: e].
- If multiple kinds of exception need to be handled at the same place, first ask why! and then a) try to handle them individually,
[] on: MyException do: [:e | self foo: e] on: MyApplicationFailure do: [:e | self bar: e].
and only when not possible: b) handle them together:
[] on: MyException,MyApplicationFailure do: [:e | self bar: e].
but c) if they already share commonality (like a sensible superclass), handle that
[] on: MyGeneralApplicationException do: [:e | self foo: e]
=-=
Conclusion: - Yes, the semantics is not straight. - I don't think it is _worth_ fixing - I fear that if it is fixed, its like green-lighting that style and I start seeing people using it for simplest stuff, and I don't want that to appear.
To be clear: I think your example should not be written as such. It should be refactored, in my view.
Best regards -Tobias
Best, Christoph Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 20:58:35 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
Hi
On 15. Jun 2023, at 20:03, Thiede, Christoph Christoph.Thiede@student.hpi.uni-potsdam.de wrote:
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that. except in very select circumstances, these Exception classes should be literal there.
Why? Just because it relieves us of the burden of worrying about copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
no.
Is it because of performance? That would surprise me, because Tobias just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
no.
Is it because of intuition? I can't imagine that. As Patrick said, #, is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
no.
Is it because you are afraid that the change might break something? Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
no.
It is because the exceptions caught should never be hidden behind a variable or sent
This one sparks joy:
[] on: MyApplicationFailure , MyApplicationPanic do: [self barf]
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
Eliot suggests that we could provide an immutable #+ on ExceptionSet instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
In python, you need language to do
try: break() except MyApplicationFailure, MyApplicationPanic as e: barf()
we can just use messages. The #, on Exception and ExceptionSet are just a bit of niceness to make things look good. There is no point in seeing them like "proper collections".
If I could, I'd raise an error when #, is sent to a non-literally constructed ExceptionSet ;P
:D
Best regards -Tobias
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] <pastedImage.png>
**) 10 timesRepeat: [Smalltalk garbageCollect]. [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC time.' NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC time.'
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors) <pastedImage.png>
Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi all, I cannot check now, but I think that I have used the pattern that Christoph describes in Smallapack. The reason for it was cross-dialect compatibility. It was better to have one dialect-dependent message defining the exception set, rather than several use places. Nicolas
Le ven. 16 juin 2023, 00:37, Tobias Pape Das.Linux@gmx.de a écrit :
Hi
On 15. Jun 2023, at 21:47, Thiede, Christoph <
Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Ah, and so implementing #, with crude semantics is your way of punishing
programmers who do not follow your idea of clean exception handling code? :P
No. I say the "correct" semantics have no place to be used.
But if we really want to discuss that:
It is because the exceptions caught should never be hidden behind a
variable or sent
Disagree!
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is
but specially, like in the tests.
This is not the example I would like to talk about. :-) Let's talk about
this one instead:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
I do prefer this very much to duplicating and leaking the specific
exception classes which are not relevant in this place.
I really do not like that style. Other languages would barf on this kind of thing and rightfully so! encapsulation is good, yes, abstraction as well. But this is just hiding stuff for no good reason.
If you need to handle multiple kinds of exceptions, thats already problematic. if you need to do it multiple times in the same method, I'd say there's an architectural problem to begin with.
Plus, we should not artificially limit the capabilities of
metaprogramming. Even though situations where some things might be rare, they always exist ... There are situations where accessing variables through #instVarNamed: makes sense. There are situations where using #ifTrue: in a cascade is helpful. There are situations where using thisContext from a return can be practical. I see no sense in Smalltalk to disallow such patterns rather than to disrecommend them ...
Come on, that's a straw man :(
So, the runtime does not really care where the Object that represent the exception come from. But readers should.
I'd say:
If possible, handle one kind of exception at once:
[] on: MyException do: [:e | self foo: e].
If multiple kinds of exception need to be handled at the same place, first ask why! and then a) try to handle them individually,
[] on: MyException do: [:e | self foo: e] on: MyApplicationFailure do: [:e | self bar: e].
and only when not possible: b) handle them together:
[] on: MyException,MyApplicationFailure do: [:e | self bar: e].
but
c) if they already share commonality (like a sensible superclass), handle that
[] on: MyGeneralApplicationException do: [:e | self foo: e]
=-=
Conclusion:
- Yes, the semantics is not straight.
- I don't think it is _worth_ fixing
- I fear that if it is fixed, its like green-lighting that style and I
start seeing people using it for simplest stuff, and I don't want that to appear.
To be clear: I think your example should not be written as such. It should be refactored, in my view.
Best regards -Tobias
Best, Christoph Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 20:58:35 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might
think
Hi
On 15. Jun 2023, at 20:03, Thiede, Christoph <
Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you
oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that. except in very select circumstances, these Exception classes should
be literal there.
Why? Just because it relieves us of the burden of worrying about
copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
no.
Is it because of performance? That would surprise me, because Tobias
just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
no.
Is it because of intuition? I can't imagine that. As Patrick said, #,
is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
no.
Is it because you are afraid that the change might break something?
Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
no.
It is because the exceptions caught should never be hidden behind a
variable or sent
This one sparks joy:
[] on: MyApplicationFailure , MyApplicationPanic do: [self barf]
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but
specially, like in the tests.
Eliot suggests that we could provide an immutable #+ on ExceptionSet
instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
In python, you need language to do
try: break() except MyApplicationFailure, MyApplicationPanic as e: barf()
we can just use messages. The #, on Exception and ExceptionSet are just
a bit of niceness to make things look good.
There is no point in seeing them like "proper collections".
If I could, I'd raise an error when #, is sent to a non-literally
constructed ExceptionSet ;P
:D
Best regards -Tobias
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] <pastedImage.png>
**) 10 timesRepeat: [Smalltalk garbageCollect]. [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC
time.'
NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC
time.'
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols
select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors)
<pastedImage.png>
Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might
think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev <
squeak-dev@lists.squeakfoundation.org> wrote:
I side with Christoph on this. Collection>>#, is clearly defined as
"return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future
without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually
store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you
might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <
Christoph.Thiede@student.hpi.uni-potsdam.demailto: Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors :=
MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would
write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors :=
MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in
TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient
degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you
might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <
squeak-dev@lists.squeakfoundation.orgmailto: squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for
copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a
cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you
anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic
and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <
christoph.thiede@student.hpi.uni-potsdam.demailto: christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the
argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of
answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider
it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
Hi Tobias,
thanks for your arguments! I still think that extracting exception( set)s is not generally a bad style, even though it is probably not used in many cases. One example is Nicolas' case of compatibility. I also don't like the plenties of "Error, Warning, Halt" that we have spread (and keep spreading) in the trunk. To me, it would read cleaner if we could hide them behind some "self interactiveExceptions". I prefer to deduplicate things and add a single place that can be changed when, for instance, Halt gets renamed to "DebuggerHalt". These examples also show that you do not always have a common superclass at hand. That might be due to the limitations of single inheritance, but when we explicate class names, we also always rule out polymorphy. I would often prefer saying
[...] onExceptionThat: [:ex | ex isError] do: [...]
to saying
[...] on: Error do: [...]
for that reason (also see my proposal for #on:when:do: from a few years ago). Regarding the single inheritance limitation, one possiblity might be to implement #handles: on Trait, but traits are rarely used and this would not fix polymorphy. I can't see why we should emphasize class names stronger in the domain of exception handling than in other domains.
However, given Eliot's comments, I agree with you that the cost for fixing might be too high (if runtime cost is what you mean by "worth fixing"). :-)
- I fear that if it is fixed, its like green-lighting that style and I start seeing people using it for simplest stuff, and I don't want that to appear.
*Presumed* that we would agree on disrecommending that style, I would still not be convinced by that conclusion. :-) People can already use #, in this way today, and for a long time, they won't notice any issues but ultimately, they will have to spend a lot of time on debugging one. This is very implicit and potentially frustrating. If we don't want to support that style, we should disallow it through the compiler like we already do for "ifTrue: [:x", "caseOf: {1->2}", et al. In any case, ExceptionSet>>#, deserves a proper comment IMO.
PS: Thank you Eliot for improving my knowledge on writing and interpreting benchmarks! :-)
Best, Christoph
--- Sent from Squeak Inbox Talk
On 2023-06-15T22:37:05+02:00, das.linux@gmx.de wrote:
Hi
On 15. Jun 2023, at 21:47, Thiede, Christoph <Christoph.Thiede(a)student.hpi.uni-potsdam.de> wrote:
Ah, and so implementing #, with crude semantics is your way of punishing programmers who do not follow your idea of clean exception handling code? :P
No. I say the "correct" semantics have no place to be used.
But if we really want to discuss that:
It is because the exceptions caught should never be hidden behind a variable or sent
Disagree!
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
This is not the example I would like to talk about. :-) Let's talk about this one instead:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
I do prefer this very much to duplicating and leaking the specific exception classes which are not relevant in this place.
I really do not like that style. Other languages would barf on this kind of thing and rightfully so! encapsulation is good, yes, abstraction as well. But this is just hiding stuff for no good reason.
If you need to handle multiple kinds of exceptions, thats already problematic. if you need to do it multiple times in the same method, I'd say there's an architectural problem to begin with.
Plus, we should not artificially limit the capabilities of metaprogramming. Even though situations where some things might be rare, they always exist ... There are situations where accessing variables through #instVarNamed: makes sense. There are situations where using #ifTrue: in a cascade is helpful. There are situations where using thisContext from a return can be practical. I see no sense in Smalltalk to disallow such patterns rather than to disrecommend them ...
Come on, that's a straw man :(
So, the runtime does not really care where the Object that represent the exception come from. But readers should.
I'd say:
If possible, handle one kind of exception at once:
[] on: MyException do: [:e | self foo: e].
If multiple kinds of exception need to be handled at the same place, first ask why! and then a) try to handle them individually,
[] on: MyException do: [:e | self foo: e] on: MyApplicationFailure do: [:e | self bar: e].
and only when not possible: b) handle them together:
[] on: MyException,MyApplicationFailure do: [:e | self bar: e].
but
c) if they already share commonality (like a sensible superclass), handle that
[] on: MyGeneralApplicationException do: [:e | self foo: e]
=-=
Conclusion:
- Yes, the semantics is not straight.
- I don't think it is _worth_ fixing
- I fear that if it is fixed, its like green-lighting that style and I start seeing people using it for simplest stuff, and I don't want that to appear.
To be clear: I think your example should not be written as such. It should be refactored, in my view.
Best regards -Tobias
Best, Christoph Von: Tobias Pape <Das.Linux(a)gmx.de> Gesendet: Donnerstag, 15. Juni 2023 20:58:35 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
Hi
On 15. Jun 2023, at 20:03, Thiede, Christoph <Christoph.Thiede(a)student.hpi.uni-potsdam.de> wrote:
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that. except in very select circumstances, these Exception classes should be literal there.
Why? Just because it relieves us of the burden of worrying about copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
no.
Is it because of performance? That would surprise me, because Tobias just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
no.
Is it because of intuition? I can't imagine that. As Patrick said, #, is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
no.
Is it because you are afraid that the change might break something? Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
no.
It is because the exceptions caught should never be hidden behind a variable or sent
This one sparks joy:
[] on: MyApplicationFailure , MyApplicationPanic do: [self barf]
This one does not spark joy:
| exceptions | exceptions := MyApplicationFailure , MyApplicationPanic. [] on: exceptions do: [self barf].
EXCEPT in the case where the exceptions are not actually meant as is but specially, like in the tests.
Eliot suggests that we could provide an immutable #+ on ExceptionSet instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
In python, you need language to do
try: break() except MyApplicationFailure, MyApplicationPanic as e: barf()
we can just use messages. The #, on Exception and ExceptionSet are just a bit of niceness to make things look good. There is no point in seeing them like "proper collections".
If I could, I'd raise an error when #, is sent to a non-literally constructed ExceptionSet ;P
:D
Best regards -Tobias
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] <pastedImage.png>
**) 10 timesRepeat: [Smalltalk garbageCollect]. [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC time.' NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC time.'
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors) <pastedImage.png>
Von: Tobias Pape <Das.Linux(a)gmx.de> Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev <squeak-dev(a)lists.squeakfoundation.org> wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda <eliot.miranda(a)gmail.com> Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede(a)student.hpi.uni-potsdam.demailto:Christoph.Thiede(a)student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux(a)gmx.demailto:Das.Linux(a)gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev(a)lists.squeakfoundation.orgmailto:squeak-dev(a)lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede(a)student.hpi.uni-potsdam.demailto:christoph.thiede(a)student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
["Trait-handles.st"]
On 21. Jun 2023, at 11:36, christoph.thiede@student.hpi.uni-potsdam.de christoph.thiede@student.hpi.uni-potsdam.de wrote:
Hi Tobias,
thanks for your arguments!
:)
I still think that extracting exception( set)s is not generally a bad style, even though it is probably not used in many cases. One example is Nicolas' case of compatibility.
I got that. I think it is a workaround tho, because we're unable to commit to a common set of Exception (ha!) amongst dialects.
I also don't like the plenties of "Error, Warning, Halt" that we have spread (and keep spreading) in the trunk. To me, it would read cleaner if we could hide them behind some "self interactiveExceptions".
But that is the point! Do not hide them. The fact that you could use a message send there is incidental. Other languages do not allow that per syntax. We don't restrict stuff by syntax there, but that does not mean we have to encourage people to (mis)use the possibilities.
Joke: Make all three an InteractiveException and catch that? (yes, that's a major refactoring *duck*)
I prefer to deduplicate things and add a single place that can be changed when, for instance, Halt gets renamed to "DebuggerHalt".
When was the last system exception renamed? Deduplication for its own merits is pointless.
These examples also show that you do not always have a common superclass at hand. That might be due to the limitations of single inheritance, but when we explicate class names, we also always rule out polymorphy. I would often prefer saying
[...] onExceptionThat: [:ex | ex isError] do: [...]
to saying
[...] on: Error do: [...]
for that reason (also see my proposal for #on:when:do: from a few years ago). Regarding the single inheritance limitation, one possiblity might be to implement #handles: on Trait, but traits are rarely used and this would not fix polymorphy. I can't see why we should emphasize class names stronger in the domain of exception handling than in other domains.
Because it is a mere quirk that Exceptions are Classes here. It is a different kind domain than other domains are.
======================== vvvvvvvvvvvvvvvvvvvvvvvv==============================
The thing is, the further you move the NAMED EXCEPTIONS away from the handling of the exceptions, the less it is "exception handling" but more "control flow with extra steps"
======================== ^^^^^^^^^^^^^^^^^^^^^^^^==============================
Also, seeing the idea of hiding excns behind messages, I instinctually assume, you're not gonna actually handle those, but rather ignore, log, or re-raise them, so what's the point?
What you CAN do is: give a name to a common handling message?
Taking the interactive stuff as example:
Myclass do: aBlock handleInteractiveBreaks: anExceptionalBlock " A proper comment on why it is advisable to handle all three the same"
^ aBlock on: Error, Warning, Halt do: anExceptionalBlock
However, given Eliot's comments, I agree with you that the cost for fixing might be too high (if runtime cost is what you mean by "worth fixing"). :-)
Nope, I don't care for the runtime costs, to be frank.
- I fear that if it is fixed, its like green-lighting that style and I start seeing people using it for simplest stuff, and I don't want that to appear.
*Presumed* that we would agree on disrecommending that style, I would still not be convinced by that conclusion. :-) People can already use #, in this way today, and for a long time, they won't notice any issues but ultimately, they will have to spend a lot of time on debugging one. This is very implicit and potentially frustrating. If we don't want to support that style, we should disallow it through the compiler like we already do for "ifTrue: [:x", "caseOf: {1->2}", et al. In any case, ExceptionSet>>#, deserves a proper comment IMO.
That, is true. PS: I am not actually against having a correct version of ExceptionSet>>#, in the image, but against the looming implications ;)
Best regards -Tobias
PS: Thank you Eliot for improving my knowledge on writing and interpreting benchmarks! :-)
Best, Christoph
Hi Christoph,
On Jun 15, 2023, at 11:03 AM, Thiede, Christoph Christoph.Thiede@student.hpi.uni-potsdam.de wrote:
Hi all,
thank you for the discussion. Unfortunately, I still don't get why you oppose my proposal. :-) Yes, you make a point in saying that this is a rare situation to occur, but you did not convince me why we should not fix the behavior for that case.
Yeah, please do not do that.
except in very select circumstances, these Exception classes should be literal there.
Why? Just because it relieves us of the burden of worrying about copying vs mutating? I can't help but think that sounds like a lazy excuse. This goes so much against the principle of least surprise.
Is it because of performance? That would surprise me, because Tobias just wrote "Let it be inefficiently", and the overhead of an immutable copy would be tiny (+1 primitiveClone, +2 primitivePushSelf, +5 bytecodes*). In practice, we are talking about maybe 7% more execution time in the context of a minimal signal+handle script**. In other words, +0.0000001 seconds per signal+handle.
Is it because of intuition? I can't imagine that. As Patrick said, #, is used for side-effect-free copying for collections and sounds as well. Any new programmer will assume the same for exception sets as well. More generally, we don't have *any* binary selectors in the image that produce side effects (with the exception of += etc. on FloatArray)***. You suggest that users could handle copies by themselves or should limit the lifecycle of exception sets. To me, all just proves that the current way is not intuitive. :-)
Is it because you are afraid that the change might break something? Well, this is hypothetically possible but quite unlikely. Plus, it would be a strong sign of bad code. We are in the trunk and have plenty of time before the next release to fix things.
Eliot suggests that we could provide an immutable #+ on ExceptionSet instead. I like this idea because #+ already has the notion of polymorphism between items and sets in the domain of Traits. However, I still don't see any advantage in keeping #, surprisingly side-effecty.
Please enlighten me. :-)
Best, Christoph
*) BenchmarkSimulator browseRecord: [[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] <pastedImage.png>
**) 10 timesRepeat: [Smalltalk garbageCollect].
Why? Once is enough. Repeating the GC has no effect other than to burn cycles. If you want all finalization activity yo complete then possibly:
Smalltalk garbageCollect. (Delay forMilliseconds: 10) wait. Smalltalk garbageCollect.
But 10 timesRepeat: is silly,
[[Error signal] on: Halt, Warning, Error do: [:ex | ex return: 42]] benchFor: 60 seconds. OLD: '707,000 per second. 1.42 microseconds per run. 8.57986 % GC time.' NEW: '656,000 per second. 1.52 microseconds per run. 13.85454 % GC time.'
This shows that approximately 7% of the execution time goes into creating the copy, or that the side-effecting #, saves 7%. That’s not insignificant. However, it shows that it uses 61% more memory (well, 61% more GC time). That’s significant. But it doesn’t compare the two directly.
Why not bench the two directly? The rate at which one consumes storage is obviously important here.
Also, you don’t state what VM (stack, JIT) you’re using, or the underlying machine. That would be helpful.
***) ToolBuilder open: (MessageNames new selectorList: (Symbol allSymbols select: [:ea | ea isInfix and: [ea isMessageSelector]]) sorted; showOnlyImplementedSelectors) <pastedImage.png>
Von: Tobias Pape Das.Linux@gmx.de Gesendet: Donnerstag, 15. Juni 2023 14:02 Uhr An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 15. Jun 2023, at 13:38, Rein, Patrick via Squeak-dev squeak-dev@lists.squeakfoundation.org wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
This is going to frustrate someone considerably in the future without any benefit.
I think it has worked up until now. "fixing" this imho is not worth it. I don't want people to actually store ExceptionSet anywhere…
best regards -Tobias
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.demailto:Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.orgmailto:squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.demailto:christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
_,,,^..^,,,_ (phone)
Hi all,
A point was raised which reminded me about "concatenation protocol" in general, which I've lived with in my own image for many years, and wanted to check your thoughts on now that it's sort of a topic of discussion (but without expressing my opinion about ExceptionSet>>#,).
On Thu, Jun 15, 2023 at 6:38 AM Rein, Patrick via Squeak-dev < squeak-dev@lists.squeakfoundation.org> wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
Exception and SequentialSound are two kinds of *singular* objects (e.g., not "Collections") that just so happen to be handy to put into collections. But, in reality, it depends mostly on the external use case rather than the type of object. *Any* class of object is useful to include into a Collection, depending on the use case.
As with other syntax sugar I enjoy like "5 minutes fromNow", since 2005 I've come to appreciate being able to express a list in Smalltalk code exactly as I can in plain writing:
myObject1, myObject2, myObject3 "{myObject1. myObject2. myObject3}"
If #, (<-- concatenation selector) should behave with similar semantics across different class hierarchies, even though ExceptionSet does not inherit from Collection (and responds false to #isCollection and also lacks the API's expected of any Collection like #size and #do:), what would you think about all classes sharing a unified concatenation protocol?
Best, Chris
This is going to frustrate someone considerably in the future without any benefit.
Cheers, Patrick
From: Eliot Miranda eliot.miranda@gmail.com Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph < Christoph.Thiede@student.hpi.uni-potsdam.demailto: Christoph.Thiede@student.hpi.uni-potsdam.de> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure
, MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure
, MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux@gmx.demailto:Das.Linux@gmx.de> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <
squeak-dev@lists.squeakfoundation.orgmailto: squeak-dev@lists.squeakfoundation.org> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for
copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <
christoph.thiede@student.hpi.uni-potsdam.demailto: christoph.thiede@student.hpi.uni-potsdam.de>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument
exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering
a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it
idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
-- _,,,^..^,,,_ best, Eliot
Hi Chris --
We have 12 implementors of #, in Squeak Trunk. The one in Collection seems to be quite generic, keeping objects together without modifying them. It would be nice to have support for #, in Object, which could just create an Array on-the-fly for the initial case.
I wonder if users would be surprised about potential side effects when working with all kinds of objects but noticing, in some cases, that the #, operation kind of modifies the domain-specific (non-collection) receiver... Hmm.... maybe all of our specializations would need a class check to fall-back to the collection-based implementation then.
Still.... is
object1, object2, object3.
really that more convenient than typing:
{ object1 . object2 . object3 }.
?
Best, Marcel Am 17.06.2023 03:14:54 schrieb Chris Muller asqueaker@gmail.com: Hi all,
A point was raised which reminded me about "concatenation protocol" in general, which I've lived with in my own image for many years, and wanted to check your thoughts on now that it's sort of a topic of discussion (but without expressing my opinion about ExceptionSet>>#,).
On Thu, Jun 15, 2023 at 6:38 AM Rein, Patrick via Squeak-dev <squeak-dev@lists.squeakfoundation.org [mailto:squeak-dev@lists.squeakfoundation.org]> wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
Exception and SequentialSound are two kinds of singular objects (e.g., not "Collections") that just so happen to be handy to put into collections. But, in reality, it depends mostly on the external use case rather than the type of object. Any class of object is useful to include into a Collection, depending on the use case.
As with other syntax sugar I enjoy like "5 minutes fromNow", since 2005 I've come to appreciate being able to express a list in Smalltalk code exactly as I can in plain writing:
myObject1, myObject2, myObject3 "{myObject1. myObject2. myObject3}"
If #, (<-- concatenation selector) should behave with similar semantics across different class hierarchies, even though ExceptionSet does not inherit from Collection (and responds false to #isCollection and also lacks the API's expected of any Collection like #size and #do:), what would you think about all classes sharing a unified concatenation protocol?
Best, Chris
This is going to frustrate someone considerably in the future without any benefit.
Cheers, Patrick
________________________________________ From: Eliot Miranda <eliot.miranda@gmail.com [mailto:eliot.miranda@gmail.com]> Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede@student.hpi.uni-potsdam.de [mailto:Christoph.Thiede@student.hpi.uni-potsdam.de]<mailto:Christoph.Thiede@student.hpi.uni-potsdam.de [mailto:Christoph.Thiede@student.hpi.uni-potsdam.de]>> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet
ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
________________________________ Von: Tobias Pape <Das.Linux@gmx.de [mailto:Das.Linux@gmx.de]<mailto:Das.Linux@gmx.de [mailto:Das.Linux@gmx.de]>> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev@lists.squeakfoundation.org [mailto:squeak-dev@lists.squeakfoundation.org]<mailto:squeak-dev@lists.squeakfoundation.org [mailto:squeak-dev@lists.squeakfoundation.org]>> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.de [mailto:christoph.thiede@student.hpi.uni-potsdam.de]<mailto:christoph.thiede@student.hpi.uni-potsdam.de [mailto:christoph.thiede@student.hpi.uni-potsdam.de]>>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
-- _,,,^..^,,,_ best, Eliot
Hi all,
-1 from my side to implementing #, for singular objects. Rather, we should rename #, on Exception to #+. :-) And aren't sounds actually plural objects (a collection of samples or instructions)? :-)
I imagine that it would be very surprising if #, mixes up singular and plural objects. It would limit polymorphy if you could not expect a reliable behavior from #, sending to an object. I can imagine a lot of funny debugging sessions arising from that.
Some brainstorming:
'plonk' , 'griffle' --> "plonkgriffle'. 'plonk' , 42 --> 'plonk42'. 42 , 43 --> #(42 43). 42 , 'plonk' --> '42plonk' or #(42 'plonk') or #(42 $p $l $o $n $k) or error? aMorph , aModel --> {a Morph . a Model}. aMutex , aMorph --> {a Mutex . a Morph} or {a Morph} or a LinkedList with a Morph or error?
If we really need that syntactic sugar, IMHO we should introduce a new selector for that, maybe #,,, or whatever. (Well, if we would design a *new* system, I would use #, for singular objects like in plain English and #+ for plural objects, but we have to maintain compatibility.)
Apart from idiomacy, note that "object1, object2, object3" is slower than "{ object1 . object2 . object3 }". In this case, it would be me who would not want to greenlight that style. :D Unless I am scripting, I also avoid #, on Strings and Arrays for the same reason and prefer using streams.
Best, Christoph
--- Sent from Squeak Inbox Talk
On 2023-06-20T11:57:53+02:00, marcel.taeumel@hpi.de wrote:
Hi Chris --
We have 12 implementors of #, in Squeak Trunk. The one in Collection seems to be quite generic, keeping objects together without modifying them. It would be nice to have support for #, in Object, which could just create an Array on-the-fly for the initial case.
I wonder if users would be surprised about potential side effects when working with all kinds of objects but noticing, in some cases, that the #, operation kind of modifies the domain-specific (non-collection) receiver... Hmm.... maybe all of our specializations would need a class check to fall-back to the collection-based implementation then.
Still.... is
object1, object2, object3.
really that more convenient than typing:
{ object1 . object2 . object3 }.
?
Best, Marcel Am 17.06.2023 03:14:54 schrieb Chris Muller <asqueaker(a)gmail.com>: Hi all,
A point was raised which reminded me about "concatenation protocol" in general, which I've lived with in my own image for many years, and wanted to check your thoughts on now that it's sort of a topic of discussion (but without expressing my opinion about ExceptionSet>>#,).
On Thu, Jun 15, 2023 at 6:38 AM Rein, Patrick via Squeak-dev <squeak-dev(a)lists.squeakfoundation.org [mailto:squeak-dev(a)lists.squeakfoundation.org]> wrote:
I side with Christoph on this. Collection>>#, is clearly defined as "return new concatenated instance made up of the receiver and the argument". Collection>>#, is even in the "copying" protocol (which is debatable, but a hint to its intention). ExceptionSet suggests that it behaves like a Collection so it should adhere to the same conventions (ExceptionSet>>#, and SequentialSound>>#, are the only two exceptions to the behavior of #,).
Exception and SequentialSound are two kinds of singular objects (e.g., not "Collections") that just so happen to be handy to put into collections. But, in reality, it depends mostly on the external use case rather than the type of object. Any class of object is useful to include into a Collection, depending on the use case.
As with other syntax sugar I enjoy like "5 minutes fromNow", since 2005 I've come to appreciate being able to express a list in Smalltalk code exactly as I can in plain writing:
myObject1, myObject2, myObject3 "{myObject1. myObject2. myObject3}"
If #, (<-- concatenation selector) should behave with similar semantics across different class hierarchies, even though ExceptionSet does not inherit from Collection (and responds false to #isCollection and also lacks the API's expected of any Collection like #size and #do:), what would you think about all classes sharing a unified concatenation protocol?
Best, Chris
This is going to frustrate someone considerably in the future without any benefit.
Cheers, Patrick
From: Eliot Miranda <eliot.miranda(a)gmail.com [mailto:eliot.miranda(a)gmail.com]> Sent: Tuesday, June 13, 2023 8:03:56 PM To: The general-purpose Squeak developers list Subject: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On Mon, Jun 12, 2023 at 7:10 AM Thiede, Christoph <Christoph.Thiede(a)student.hpi.uni-potsdam.de [mailto:Christoph.Thiede(a)student.hpi.uni-potsdam.de]<mailto:Christoph.Thiede(a)student.hpi.uni-potsdam.de [mailto:Christoph.Thiede(a)student.hpi.uni-potsdam.de]>> wrote:
Hi all,
here is a (though theoretic) example:
[self doSomething]
on: self class applicationErrors
do: [...]
[self doSomethingElse]
on: self class applicationErrors , self class systemErrors
do: [...]
and on the class side:
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt]
Given the current semantics (which I agree are justified) I would write these last two as
class>>applicationErrors
^ ApplicationErrors ifNil: [ApplicationErrors := MyApplicationFailure , MyApplicationPanic] ifNotNil: [:anExceptionSet| anExceptionSet copy]
class>>systemErrors
^ SystemErrors ifNil: [SystemErrors := Error , Warning, Halt] ifNotNil: [:anExceptionSet| anExceptionSet copy]
or I would write the handler with a copy:
[self doSomethingElse]
on: self class applicationErrors copy, self class systemErrors
do: [...]
But perhaps we could add #+ as the selector that answers a copy:
Exception>+ anExceptionSet ^self , anExceptionSet
ExceptionSet>+ anExceptionSet ^self copy, anExceptionSet
While the example is theoretic, we have a similar pattern already in TestResult class>>#allErrors, and I also apply that pattern in some of my own projects. Once you try to optimize that pattern by using a cache, confusion is likely to arise. Even worse, the current behavior of #, forces us not to optimize the code (if I invoke the exception handler many many times, constructing a cache with 2x primitiveNew once will obviously be faster than using 1x primitiveNew every time).
(By the way: The example shows that #, may construct an inefficient degenerated linked list, but that's another story.)
Best,
Christoph
Von: Tobias Pape <Das.Linux(a)gmx.de [mailto:Das.Linux(a)gmx.de]<mailto:Das.Linux(a)gmx.de [mailto:Das.Linux(a)gmx.de]>> Gesendet: Montag, 12. Juni 2023 15:54:46 An: The general-purpose Squeak developers list Betreff: [squeak-dev] Re: ExceptionSet>>#, does not do what you might think
On 12. Jun 2023, at 15:10, Marcel Taeumel via Squeak-dev <squeak-dev(a)lists.squeakfoundation.org [mailto:squeak-dev(a)lists.squeakfoundation.org]<mailto:squeak-dev(a)lists.squeakfoundation.org [mailto:squeak-dev(a)lists.squeakfoundation.org]>> wrote:
Hi Christoph --
What realistic use case is there that makes a difference for copy-vs-change?
So far, I only used exception sets in:
... on: Error, Warning do: ... knownEx := Error, Warning. ... on: knownEx do: ...
So, quite short-living and fast to create. When would you need a cascade?
I agree.
Yes, its conceptually ugly. No, it has no impact whatsoever and the copy does not gain you anything.
It's not like you would write code like
foo | exs |
exs := Error, Warn
[ ... ] on: exs, Halt do: [ ... ]. [ ... ] on: exs, MessageNotUnderstood do: [ ... ].
It would break there, yes. But I'd argue that code is not idiomatic and a problem in itself.
Best regards -Tobias
Best, Marcel
Am 12.06.2023 14:23:53 schrieb Thiede, Christoph <christoph.thiede(a)student.hpi.uni-potsdam.de [mailto:christoph.thiede(a)student.hpi.uni-potsdam.de]<mailto:christoph.thiede(a)student.hpi.uni-potsdam.de [mailto:christoph.thiede(a)student.hpi.uni-potsdam.de]>>:
Hi all,
ExceptionSet >> , anException "Return an exception set that contains the receiver and the argument exception. This is commonly used to specify a set of exception selectors for an exception handler."
self add: anException. ^self
That means that #, actually modifies the receiver instead of answering a copy. Thus, we can observe the following:
Error , Warning , Halt; handles: Halt new "true"
Should we change that? It's really confusing and I would consider it idiosyncratic. On the other hand, code that actually wants to copy an ExceptionSet seems to be pretty rare, and a side-effect-free #, would be more expensive for the interpreter and for the GC.
Best,
Christoph
-- _,,,^..^,,,_ best, Eliot
I imagine that it would be very surprising if #, mixes up singular and plural objects.
For what it's worth, in my images I have #orMore, #orMoreCollect: and #orMoreDo: that consider their receiver as a collection.
It's tricky though: #orMore on a non-collection return an Array wrapping the receiver, but of course Array is an arbitrary choice here, and I also implemented these methods to consider a String as a non-collection, so that I can do things like
drumPattern orMoreDo: [:ea | whatever doSomethingWith: #ea]
where drumPattern can be #(bim bam boum) but also simply #boum.
I found that useful, but it is certainly very idiosyncratic.
Stef
drumPattern orMoreDo: [:ea | whatever doSomethingWith: #ea]
I meant
drumPattern orMoreDo: [:ea | whatever doSomethingWith: ea]
and, to be clear:
42 orMore -> #(42) {42} orMore -> #(42) (Set with: 42) orMore -> a Set(42)
Stef
Hi Stef --
In Vivide, I have #asList (and #isList) for that:
Best, Marcel Am 21.06.2023 13:23:53 schrieb Stéphane Rollandin lecteur@zogotounga.net:
drumPattern orMoreDo: [:ea | whatever doSomethingWith: #ea]
I meant
drumPattern orMoreDo: [:ea | whatever doSomethingWith: ea]
and, to be clear:
42 orMore -> #(42) {42} orMore -> #(42) (Set with: 42) orMore -> a Set(42)
Stef
Hi Christoph and all,
-1 from my side to implementing #, for singular objects. Rather, we should
rename #, on Exception to #+. :-)
+1 except #+ is confusing, I hope you'll go with #|, because it reads like "or", which is the correct semantic:
[ socket sendSomeData ] on: Timeout | ConnectionClosed do: [ : err | ... ]
That reads as, "on Timeout OR ConnectionClosed do..." #+ would make the code read like "on Timeout AND ConnectionClosed do...", which is confusing enough it would compel developers to need to constantly check the implementation of #+. Plus (no pun intended), it overloads the semantic meaning of #+ elsewhere, which is associated with addition. #+ may mean concatenation in other languages, but not Smalltalk.
And aren't sounds actually plural objects (a collection of samples or instructions)? :-)
I imagine that it would be very surprising if #, mixes up singular and plural objects. It would limit polymorphy if you could not expect a reliable behavior from #, sending to an object. I can imagine a lot of funny debugging sessions arising from that.
Some brainstorming:
'plonk' , 'griffle' --> "plonkgriffle'. 'plonk' , 42 --> 'plonk42'. 42 , 43 --> #(42 43). 42 , 'plonk' --> '42plonk' or #(42 'plonk') or #(42 $p $l $o $n $k) or error? aMorph , aModel --> {a Morph . a Model}. aMutex , aMorph --> {a Mutex . a Morph} or {a Morph} or a LinkedList with a Morph or error?
All good observations. As with other cases in the library, the class of the receiver determines the type of output (bytes or pointers). I should've included the package which demonstrates and would've addressed some of those. I've included it in this post (see BrpExtensions).
Reviewing this reminds me what this package is really about -- an idea similar, I think, to Stéphane's #orMore -- where you can create a homogeneity with plurals and singulars within your API's, allowing you to pass singular objects to method arguments that might otherwise expect a collection.
If we really need that syntactic sugar, IMHO we should introduce a new selector for that, maybe #,,, or whatever. (Well, if we would design a *new* system, I would use #, for singular objects like in plain English and #+ for plural objects, but we have to maintain compatibility.)
Instead of advocacy for inclusion in trunk, I really just felt the discussion of whether Exception>>#, should match Array>>#, could be enhanced by broaching the question of it for all objects. Should such decisions be influenced by semantic conformity or pragmatic use? It's basically impossible to graft a single inheritance hierarchy onto all the meanings and nuances of all the subclasses -- so we craft the best basic hierarchy we can, and then fine-sculpt it with combinations of #subclassResponsibility and #shouldNotImplement.
Apart from idiomacy, note that "object1, object2, object3" is slower than
"{ object1 . object2 . object3 }". In this case, it would be me who would not want to greenlight that style. :D Unless I am scripting, I also avoid #, on Strings and Arrays for the same reason and prefer using streams.
Agree, but a concatenation API has its places and purposes (see above). :)
Best, Chris
As a tiny whine, I find it a smidge annoying that we adopted the same character symbol for "sometihng to do with temporary variables" and "logical or thing". I find the example below quite jarring because of that.
On 2023-06-21, at 2:39 PM, Chris Muller asqueaker@gmail.com wrote:
+1 except #+ is confusing, I hope you'll go with #|, because it reads like "or", which is the correct semantic:
[ socket sendSomeData ] on: Timeout | ConnectionClosed do: [ : err | ... ]
An alternative approach that would skip this particular complaint is
[ socket sendSomeData ] on: {Timeout . ConnectionClosed} do: [ : err | ... ]
Though I'm sure there could be issues with this too.
tim -- tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim CChheecckk yyoouurr dduupplleexx sswwiittcchh..
Vertical bar is already a logical OR in Smalltalk, so using it for exceptions makes sense in my opinion.
- Jon
On Wed, 21 Jun 2023 at 17:53, Tim Rowledge tim@rowledge.org wrote:
As a tiny whine, I find it a smidge annoying that we adopted the same character symbol for "sometihng to do with temporary variables" and "logical or thing". I find the example below quite jarring because of that.
On 2023-06-21, at 2:39 PM, Chris Muller asqueaker@gmail.com wrote:
+1 except #+ is confusing, I hope you'll go with #|, because it reads
like "or", which is the correct semantic:
[ socket sendSomeData ] on: Timeout | ConnectionClosed do: [ : err | ... ]
An alternative approach that would skip this particular complaint is
[ socket sendSomeData ] on: {Timeout . ConnectionClosed} do: [ : err | ... ]
Though I'm sure there could be issues with this too.
tim
tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim CChheecckk yyoouurr dduupplleexx sswwiittcchh..
On 21. Jun 2023, at 23:52, Tim Rowledge tim@rowledge.org wrote:
As a tiny whine, I find it a smidge annoying that we adopted the same character symbol for "sometihng to do with temporary variables" and "logical or thing". I find the example below quite jarring because of that.
On 2023-06-21, at 2:39 PM, Chris Muller asqueaker@gmail.com wrote:
+1 except #+ is confusing, I hope you'll go with #|, because it reads like "or", which is the correct semantic:
[ socket sendSomeData ] on: Timeout | ConnectionClosed do: [ : err | ... ]
An alternative approach that would skip this particular complaint is
[ socket sendSomeData ] on: {Timeout . ConnectionClosed} do: [ : err | ... ]
Though I'm sure there could be issues with this too.
Oh dear, so we have now the proposal of #+ and #| and the dynamic Array notation, to counter the semantic problem of #,. I'm losing track...
OK, so, Action proposal:
1. Christoph can go ahead and fix #, on ExcnSet 2. We figure out why a proliferation of stored-away exception sets could happen and assess its problems. 3. ??? 4. Fun.
(or something?)
Best regards -Tobias
squeak-dev@lists.squeakfoundation.org