Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-jar.1532.mcz
==================== Summary ====================
Name: Kernel-jar.1532
Author: jar
Time: 9 November 2023, 11:23:12.591819 pm
UUID: 91eef5d6-745d-1d4f-a278-0397357c3841
Ancestors: Kernel-dtl.1531
fix Context >> #homeMethod; the following will now answer true:
[thisContext homeMethod] value = thisContext homeMethod
=============== Diff against Kernel-dtl.1531 ===============
Item was changed:
----- Method: Context>>homeMethod (in category 'accessing') -----
homeMethod
"Answer the home method associated with the receiver.
This is polymorphic with BlockClosure, CompiledCode, Context etc."
+ ^self method homeMethod!
- ^self method!
A new version of KernelTests was added to project The Inbox:
http://source.squeak.org/inbox/KernelTests-jr.446.mcz
==================== Summary ====================
Name: KernelTests-jr.446
Author: jr
Time: 9 November 2023, 3:10:49.238163 pm
UUID: 09c3e782-fb6c-1a4e-8287-d2567640f438
Ancestors: KernelTests-pre.445
Complements Kernel-jr.1532
Test that notifications that are not meant to interrupt the control flow are not caught while evaluating a future send.
The test example `Object future comment` was provided by Christoph Thiede (ct).
=============== Diff against KernelTests-pre.445 ===============
Item was added:
+ ----- Method: FutureTest>>testNotificationsAreNotCaught (in category 'tests') -----
+ testNotificationsAreNotCaught
+ "The deferred evaluation below uses CurrentReadOnlySourceFiles. The error handling of the future promise must not interfere with this Notification."
+ | p1 |
+ p1 := Object future comment.
+ self waitUntil: [p1 isResolved] orCycleCount: 1.
+ self assert: p1 isResolved.
+ !
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-jr.1532.mcz
==================== Summary ====================
Name: Kernel-jr.1532
Author: jr
Time: 9 November 2023, 3:08:48.989163 pm
UUID: 5af29860-7431-0b48-b551-f59dcc85b3b8
Ancestors: Kernel-dtl.1531
Future evaluations should not catch exceptions that are not supposed to be caught or not meant to abort any control flow. This includes Notifications such as CurrentReadOnlySourceFiles.
=============== Diff against Kernel-dtl.1531 ===============
Item was changed:
----- Method: Promise>>fulfillWith:passErrors: (in category 'resolving') -----
fulfillWith: aBlock passErrors: aBoolean
"Evaluate aBlock. If it signals an exception, reject this promise with the exception
as the argument; if it returns a value [or another Promise], resolve this promise
with the result.
If aBoolean is true, and an exception is signaled, it is passed out to the caller.
If aBoolean is false, signaled exceptions are considered handled after the promise
has been rejected."
[ self resolveWith: aBlock value ]
+ on: Error
- on: Exception
do: [ :ex |
+ self rejectWith: ex.
+ aBoolean ifTrue: [ ex pass ] ]!
- (ex isKindOf: Halt)
- ifTrue: [ex pass]
- ifFalse: [
- self rejectWith: ex.
- aBoolean ifTrue: [ ex pass ] ]]!
Patrick Rein uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-pre.857.mcz
==================== Summary ====================
Name: Collections-pre.857
Author: pre
Time: 4 October 2019, 11:04:30.363303 am
UUID: 5ef00b65-3884-c445-b276-0cc01f0b10a1
Ancestors: Collections-pre.856
Adds startOfHeader to Character, adds empty abstract implementations of scanFrom:, writeScanOn: to TextAttribute to allow for Texts which include TextAttributes which do not implement serialization to still be serialized, adds a comment to these methods.
=============== Diff against Collections-pre.856 ===============
Item was added:
+ ----- Method: Character class>>startOfHeader (in category 'accessing untypeable characters') -----
+ startOfHeader
+
+ ^ self value: 1 !
Item was added:
+ ----- Method: TextAttribute class>>scanFrom: (in category 'fileIn/Out') -----
+ scanFrom: strm
+ "Read the text attribute properties from the stream. When this method has
+ been called the concrete TextAttribute class has already been selected via
+ scanCharacter. (see TextAttribute class>>#newFrom:).
+ For writing the format see TextAttribute>>#writeScanOn:"!
Item was added:
+ ----- Method: TextAttribute>>writeScanOn: (in category 'fileIn/fileOut') -----
+ writeScanOn: strm
+ "Implement this method for a text attribute to define how it it should be written
+ to a serialized form of a text object. The form should correspond to the source
+ file format, i.e. use a scan character to denote its subclass.
+ As TextAttributes are stored in RunArrays, this method is mostly called from RunArray>>#write scan.
+ For reading the written information see TextAttribute class>>#scanFrom:"
+
+ "Do nothing because of abstract class"!
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-jar.1532.mcz
==================== Summary ====================
Name: Kernel-jar.1532
Author: jar
Time: 9 November 2023, 11:23:12.591819 pm
UUID: 91eef5d6-745d-1d4f-a278-0397357c3841
Ancestors: Kernel-dtl.1531
fix Context >> #homeMethod; the following will now answer true:
[thisContext homeMethod] value = thisContext homeMethod
=============== Diff against Kernel-dtl.1531 ===============
Item was changed:
----- Method: Context>>homeMethod (in category 'accessing') -----
homeMethod
"Answer the home method associated with the receiver.
This is polymorphic with BlockClosure, CompiledCode, Context etc."
+ ^self method homeMethod!
- ^self method!
Hi all,
Tony has recently fixed our Promise implementation to make it more
Promises/A+ compliant, thank you!
In the discussion that lead to this fix [1], I already pointed out a
difference between exceptions in Smalltalk and in JavaScript, where
the Promises/A+ specification originates: Smalltalk exceptions can be
resumed, while JavaScript exceptions cannot be resumed and always
unroll the stack.
The spec [2] says that if the onFulfilled or onRejected callback of a
#then call on a promise throws an exception, then the promise returned
by the #then call shall be rejected with the exception thrown.
Our current Promise implementation matches this for the blocks
supplied to #then:, #ifRejected: or #then:ifRejected, by catching all
Errors in the blocks and rejecting the promise. But this does not
allow a Squeak user to deal with exceptions in a debugger if they are
signalled in the callbacks, because they are caught. The same also
applies to #future promises. The latter are not really covered by the
Promises/A+ spec (because it does not force the resolution or
rejection of a promise that is not the result of a #then, and there is
no #future in JavaScript), but futures exhibit the same problem of not
being resumable in the debugger. Example:
promise := 1 future / 0. "<= inspect it => promise is rejected,
regardless of your actions in the debugger"
Number compile: 'methodWithTypo ^ self asstring'.
promise := 1 future methodWithTypo. "<= inspect it => promise is
rejected, no chance to fix the misspelling of asString in the debugger
and proceed"
I could imagine instead letting all exceptions pass during the future
or callback block evaluation, and only reject the promise if the
evaluation is eventually curtailed due to the exception (be it an
Error or not, think of Warning or ModificationForbidden). Example
expectations:
promise := 1 future / 0. "<= inspect it, press Proceed in the
debugger, => promise is resolved"
promise := 1 future / 0. "<= inspect it, press Abandon in the
debugger, => promise is rejected"
promise := 1 future methodWithTypo. "<= inspect it, fix the typo of
asString in the debugger, proceed, => promise is resolved with '1'"
It could be done by fulfilling a Promise about aBlock similar to this:
[ self resolveWith: aBlock value ]
on: Exception
do: [ :ex | | resumed |
resumed := false.
[ | result |
result := ex outer.
resumed := true.
ex resume: result]
ifCurtailed: [resumed ifFalse: [self future rejectWith: ex]]]
(Find the current implementations here:
Promise>>#fulfillWith:passErrors: and Promise>>#then:ifRejected:)
Note that the #outer send would only trigger handlers in the
Project/World loop, or the defaultAction of the exception. The #future
in front of #rejectWith: is there to avoid curtailing the unwind block
context of ifCurtailed: itself if there are further errors in the
rejection callbacks of the promise. The behavior of non-local exits
from unwind contexts is undefined in the Smalltalk ANSI standard (just
like resume: or return: in a defaultAction, or not sending resume: or
return: in an on:do: exception handler at all -- VA Smalltalk
interprets that as resume, while Squeak does return, for example).
This implementation would also allow all deferred Notifications to
pass and not reject the promise. That is because true notifications
just resume silently if they are not handled.
promise := [Notification signal: 'hi there'. 42] future value. "<=
inspect it => Expected: resolved with 42. Actual (today): it is
needlessly rejected with Notification 'hi there'"
Pressing Proceed in the debugger on officially non-resumable errors
(which is possible) would also not reject the promise. But further
errors/debuggers are likely to appear, of which one may eventually be
used to abort the execution. If the execution finishes after
repeatedly pressing Proceed, then fine, resolve the promise with
whatever the outcome was.
promise := [self error: 'Fatal error'. 42] future value. "<= inspect
it, proceed after the so-called fatal error, => Expected: resolved
with 42. Actual: there is no debugger, the promise is immediately
rejected."
promise := [1 / 0 + 3] future value. "<= Cannot be resumed/proceeded
because if ZeroDivide is resumed, it will return the exception, and
ZeroDivide does not understand +, which cannot be resumed without
changing the code. So you'd have to curtail the block execution =>
Expected: rejected with ZeroDivide or MessageNotUnderstood (depending
on when you press Abandon or recompile the DoIt)."
promise := [1 / 0 + 3] future value. "... or instead of changing the
code or aborting, you could choose 'return entered value' in one of
the debuggers, and thereby complete the evaluation of the block =>
Expected: resolved with whatever you entered to return in the
debugger"
Promises with whenRejected:/ifRejected: callbacks would no longer
swallow errors, and would only be rejected when the user aborts in the
debuggers, or if the future execution catches errors by itself and
converts them to rejected promises, so the future promise will also be
rejected. This could pose a compatibility problem for existing code.
promise := (1 future / 0) then: [:result | result + 3] ifRejected:
[:reason | #cancelled]. "<= inspect it => Actual: resolved with
#cancelled immediately. Expected with my proposed changes: it would
first show the ZeroDivide debugger, which you can abandon to resolve
with #cancelled, or proceed to a MessageNotUnderstood +. If you
abandon the MNU, the promise would be rejected with the MNU, not
#cancelled, in accordance with the Promises/A+ spec."
How to get back a catch-all->reject-immediately future under these
circumstances:
promise := [[1 / 0] on: Error do: [:e | e return: (Promise new
rejectWith: e)]] future value.
promise := [1 future + 1 then: [:n | [n / 0] on: Error do: [:e | e
return: (Promise new rejectWith: e)]] future value.
We could also introduce a convenience constructor for
immediately-rejected promises like in JavaScript: Promise rejected: e.
Or a convenience exception handler: [...] rejectOn: Error. Or [...]
rejectIfCurtailed (the fullfill/then methods would probably use this
as well).
What do you think?
As Tom Beckmann has already suggested in the last thread on the topic
[1], I could also use a custom class of Promise to get just the
behavior I want. But then I cannot solve it for the use of #future. At
least not without patching something about the compiler in my package
preamble... ;-)
[1] http://lists.squeakfoundation.org/pipermail/squeak-dev/2020-April/208546.ht…
[2] https://promisesaplus.com/
Kind regards,
Jakob
A new version of KernelTests was added to project The Inbox:
http://source.squeak.org/inbox/KernelTests-lrnp.447.mcz
==================== Summary ====================
Name: KernelTests-lrnp.447
Author: mt
Time: 9 November 2023, 11:37:53.664378 am
UUID: bcfb3415-9980-e442-ba18-2cb22fcf5089
Ancestors: KernelTests-pre.445
Rename an lrnp contribution that had an incompatible version name.
KernelTests.lrnp-20231108.446
- test assumptions about the home method and CompiledCode split
=============== Diff against KernelTests-pre.445 ===============
Item was added:
+ ----- Method: ContextTest>>testHomeMethod (in category 'tests') -----
+ testHomeMethod
+
+ self assert: [thisContext homeMethod] value = thisContext homeMethod!
Item was added:
+ ----- Method: ContextTest>>testPragmaSearch (in category 'tests') -----
+ testPragmaSearch
+
+ <aTestPragma>
+ self assert: (thisContext method hasPragma: #aTestPragma).
+ self deny: [thisContext method hasPragma: #aTestPragma]!
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-lrnp.1535.mcz
==================== Summary ====================
Name: Kernel-lrnp.1535
Author: mt
Time: 9 November 2023, 11:35:47.162378 am
UUID: 8f0c1c65-3c48-c44b-8492-5d6c32cf4174
Ancestors: Kernel-dtl.1531
Combines two lrnp contributions that had an incompatible version name.
Kernel.lrnp-20231108.1534
- enforce more strict pragma access
- treat pragma access like for #primitive : they are stored on the CompiledMethod, so have CompiledBlock answer not found even if its home method has one.
- Also move #hasPragma: to CompiledCode to avoid the caller needing to add a guard.
- Complements the new testPragmaAccess Context test in KernelTests.lrnp-20231108.446.
- I don't know if this is backwards-incompatible due to mixed use of homeMethod and method on Context. I didn't include properties because that does certainly break at least one method.
Kernel.lrnp-20231108.1533
- cause #homeMethod to answer a CompiledMethod
- causes "[thisContext homeMethod] value = thisContext homeMethod" to answer true.
=============== Diff against Kernel-dtl.1531 ===============
Item was changed:
----- Method: BlockClosure>>homeMethod (in category 'accessing') -----
homeMethod
"Answer the home method associated with the receiver.
This is polymorphic with BlockClosure, CompiledCode, Context etc."
+ | maybe |
+ maybe := self method.
+ maybe ifNil: [^nil].
+ ^ maybe homeMethod!
- ^self method!
Item was removed:
- ----- Method: CompiledBlock>>pragmaAt: (in category 'accessing-pragmas & properties') -----
- pragmaAt: aKey
- "Answer the pragma with selector aKey, or nil if none."
- ^self homeMethod pragmaAt: aKey!
Item was removed:
- ----- Method: CompiledBlock>>pragmas (in category 'accessing-pragmas & properties') -----
- pragmas
- ^self homeMethod pragmas!
Item was removed:
- ----- Method: CompiledBlock>>pragmasAt: (in category 'accessing-pragmas & properties') -----
- pragmasAt: aSelector
- "Answer all pragmas with selector aSelector."
- ^self homeMethod pragmasAt: aSelector!
Item was added:
+ ----- Method: CompiledCode>>hasPragma: (in category 'accessing-pragmas & properties') -----
+ hasPragma: aSymbol
+
+ ^ (self pragmaAt: aSymbol) notNil!
Item was added:
+ ----- Method: CompiledCode>>pragmaAt: (in category 'accessing-pragmas & properties') -----
+ pragmaAt: aKey
+ "Answer the pragma with selector aKey, or nil if none."
+ ^nil!
Item was added:
+ ----- Method: CompiledCode>>pragmas (in category 'accessing-pragmas & properties') -----
+ pragmas
+ ^#()!
Item was added:
+ ----- Method: CompiledCode>>pragmasAt: (in category 'accessing-pragmas & properties') -----
+ pragmasAt: aSelector
+ "Answer all pragmas with selector aSelector."
+ ^#()!
Item was removed:
- ----- Method: CompiledMethod>>hasPragma: (in category 'accessing-pragmas & properties') -----
- hasPragma: aSymbol
-
- ^ (self pragmaAt: aSymbol) notNil!
Item was changed:
----- Method: Context>>homeMethod (in category 'accessing') -----
homeMethod
"Answer the home method associated with the receiver.
This is polymorphic with BlockClosure, CompiledCode, Context etc."
+ | maybe |
+ maybe := self method.
+ ^ (maybe isKindOf: CompiledMethod)
+ ifTrue: maybe
+ ifFalse: [maybe homeMethod]!
- ^self method!
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel.lrnp-20231108.1533.mcz
==================== Summary ====================
Name: Kernel.lrnp-20231108.1533
Author: lrnp
Time: 8 November 2023, 4:25:22.251462 pm
UUID: 908d574d-93a7-45a8-aee1-32304f8d7955
Ancestors: Kernel-dtl.1531
cause #homeMethod to answer a CompiledMethod
Causes
[thisContext homeMethod] value = thisContext homeMethod
to answer true.
=============== Diff against Kernel-dtl.1531 ===============
Item was changed:
----- Method: BlockClosure>>homeMethod (in category 'accessing') -----
homeMethod
"Answer the home method associated with the receiver.
This is polymorphic with BlockClosure, CompiledCode, Context etc."
+ | maybe |
+ maybe := self method.
+ maybe ifNil: [^nil].
+ ^ maybe homeMethod!
- ^self method!
Item was changed:
----- Method: Context>>homeMethod (in category 'accessing') -----
homeMethod
"Answer the home method associated with the receiver.
This is polymorphic with BlockClosure, CompiledCode, Context etc."
+ | maybe |
+ maybe := self method.
+ ^ (maybe isKindOf: CompiledMethod)
+ ifTrue: maybe
+ ifFalse: [maybe homeMethod]!
- ^self method!