From lproven at gmail.com Mon Mar 1 00:00:36 2021 From: lproven at gmail.com (Liam Proven) Date: Mon, 1 Mar 2021 01:00:36 +0100 Subject: [squeak-dev] seL4 Microkernel: How small can the shim be? In-Reply-To: References: <2e1c7a819dbffc813b8b7210055e8ef3@whidbey.com> <81CC89CC-EA56-40CF-82B3-EA4BC690FA9D@rowledge.org> Message-ID: On Sun, 28 Feb 2021 at 19:32, tim Rowledge wrote: > > Good; not enough people know of it. Agreed. > I was involved before it was even a Thing, and kept using as my main work system (even coercing assorted research labs in Silicon Valley to support me in this insanity) until about 2010. :-) Did you know or work with Paul Fellows? We have a mutual friend and I managed to arrange for him to do a talk at ROUGOL back in 2012. It was fascinating. There's a transcript here: http://www.rougol.jellybaby.net/meetings/2012/PaulFellows/ > I'd dispute a few of your assertions there but, yeah, mostly. I don't think one could 'improve' RISC OS into a usefully modern OS but I do think one could create a modern OS with the 'spirit' of RISC OS. And nobody would use it. :-( Corrections welcomed, as they say. A friend of mine was the late great UK IT journalist Guy Kewney, an exceptional writer and commentator on this field. One of my favourite bits of his -- I can only paraphrase it, sadly, I've never found it online -- was a review of WordPerfect 5. He said, roughly: "WordPerfect 4.2 was pretty much the best word-processor on any platform in the world. It had outcompeted all the competition on everything else. It did everything you could ever want, and it did it quickly and well with an elegant if odd user interface. Looking at WordPerfect 5, therefore, I am driven to wonder how the management of the company decided to create this. Did they look at each other and say, 'So, we have a great bicycle here. Everyone agrees it's the best bicycle in the world. So what we're going to do it, we're going to put 11 more wheels on it." WP5 added pull-down CUA menus, bolted rather clumsily on top of 4.2's function-key based controls. It was bigger, slower, buggier, took more memory, and had an ugly 2nd UI as well as its original one. It's funny, looking back now, that the _next_ release, WordPerfect 5.1 for DOS, is the one that almost everyone today looks back upon as being the peak of the DOS line. Me -- supporting it back then, but never being a big fan -- I have WordPerfect 6 for DOS running on PC-DOS 7.1 on a Lenovo Thinkpad. It was lambasted for being big and slow when it was new. Now, on decade-old kit, it's blindingly fast, and seems elegant, tiny and polished. Funny how time changes our perceptions. I think I agree with you. It might be possible, with a tonne of work, to modernise RISC OS into something with pre-emptive multitasking, multi-threading, multiple processor core support, wifi and bluetooth and OpenGL and a 3D-composited desktop and all the other things people expect in a modern OS. But it wouldn't really be RISC OS any more. Its charm is that it's tiny and fast and efficient. It's a great bicycle but if anyone tries to turn it into a motorcycle, I fear it will be a poor one. There _are_ some things in that blogpost that I got wrong -- I clarify some in the comments. RISC OS Developments are porting the OpenBSD TCP-IP stack to RO5. This will give it IPv6 support and wifi as well with any luck. Bluetooth is far less important, TBH. And a chap in the ROOL forum has a proof-of-concept multi-core add-on working. Another chap has NetBSD executing on one ARM core while RISC OS executes on another, which is splendidly impressive if slightly insane. Apparently there is a plan for ARM64 support, too. It's a bit like Apple did with Classic MacOS on PowerPC: run a tiny kernel underneath the OS that emulates the old platform on-the-fly. Apparently ARM32 emulation on ARM64 works well and is very fast indeed. It may get these modernisations anyway. I will be very interested to see how it goes. I am very tempted to get a RISC OS PineBook as it is. > Pretty much the case. It *was* a simple design, but grew .... complicated, over the decades. I agree. > > Other interesting lightweight vintage OSes which are now FOSS: > Mention not these primitive abacus's. :-D Excellent. Very nearly a Douglas Adams quote! I do have a QL, but I barely know how to operate the thing. SMSQ/E does seem to have evolved into an interesting, capable OS in the end, though... > Well, as Ken says, that's pretty much an empty set. I don't think it is. I submit that the Oberon OS ticks pretty much every single box. Only the A2 variant is SMP-capable, but I have it running in VMs and on the bare metal here and it's very impressive indeed. There used to be a StrongARM version. The code is already cross-platform and runs or has run on x86, NatSemi 32000, ARM, and RISC5. I suspect that getting it working again on modern ARM would not be that hard. > I'd certainly not accept the 'not jitted' criterion since I am going to stand on my claim that it would make it much easier to write and maintain a flexible system. I have to defer to your superior knowledge on this. I just want to remind folks that the reason I'm here is that I'd really like to see Squeak running on A2... I think it could be a good partnership. > I'd also point out that the OS per se has nothing at all to do with whether an in-use system is suited to general users or experts - that's the domain of the software running on top of/in the OS. With sufficient work and inspiration one could even make Windows tolerable at the user level. Very true. > If you can find a way to engage a few tens of millions of plausible currency units then there may be avenues to success. Some of us on this very list have seriously tried in the past but if you have any way to get it done... fabulous! Aye, there's the rub. -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From m at jaromir.net Mon Mar 1 09:55:09 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 1 Mar 2021 03:55:09 -0600 (CST) Subject: [squeak-dev] The Trunk: Kernel-codefrau.1374.mcz In-Reply-To: References: Message-ID: <1614592509436-0.post@n4.nabble.com> Hi, something's wrong - method's bytecode in explorer not showing... displaying an error instead. see encl. best, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Mon Mar 1 10:14:13 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 1 Mar 2021 11:14:13 +0100 Subject: [squeak-dev] The Trunk: Kernel-codefrau.1374.mcz In-Reply-To: <1614592509436-0.post@n4.nabble.com> References: <1614592509436-0.post@n4.nabble.com> Message-ID: Hi Jaromir. Which "do it" did you debug? Works in my image. The MNU issue in your screenshot is not possible. ByteCodeEncoder class implements #bytecodeSetName. :-) Best, Marcel Am 01.03.2021 10:55:18 schrieb Jaromir Matas : Hi, something's wrong - method's bytecode in explorer not showing... displaying an error instead. see encl. best, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Mon Mar 1 10:19:28 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 1 Mar 2021 10:19:28 0000 Subject: [squeak-dev] The Trunk: Tools-mt.1027.mcz Message-ID: Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1027.mcz ==================== Summary ==================== Name: Tools-mt.1027 Author: mt Time: 1 March 2021, 11:19:25.66938 am UUID: 4a78193f-b0aa-1b42-9f4a-d588b979d0b6 Ancestors: Tools-mt.1026 Let warnings appear as "normal" as possible via #debugException:. Note that the "normal" contents are prepared only in ToolSet >> #handleWarning: for unhandled warnings, which is transparent to the signaler. This interface, however, is for exception handlers that want to allow for post-exception debugging, which can also catch warnings. =============== Diff against Tools-mt.1026 =============== Item was changed: ----- Method: StandardToolSet class>>debugException: (in category 'debugging') ----- debugException: anException "For convenience. Construct a helper process to debug an exception that occurred in the active process later on so that the active process can (try to) resume. Uses a temporary variable to access and copy the signaler context now before it gets GC'ed." | helperProcess | helperProcess := (Process forContext: anException signalerContext copyStack priority: Processor activeProcess priority) shouldResumeFromDebugger: false; yourself. Project current addDeferredUIMessage: [ helperProcess debugWithTitle: anException description + full: false + contents: ((anException isKindOf: Warning) + ifTrue: [anException messageText])].! - full: false].! From m at jaromir.net Mon Mar 1 10:46:55 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 1 Mar 2021 04:46:55 -0600 (CST) Subject: [squeak-dev] The Trunk: Kernel-codefrau.1374.mcz In-Reply-To: References: <1614592509436-0.post@n4.nabble.com> Message-ID: <1614595615096-0.post@n4.nabble.com> Hi, I just did thisContext explore and noticed the difference... Prior (Kernel-eem.1373) it shows this: I'm on Squeak6.0alpha-20182-64bit, VM [CoInterpreterPrimitives VMMaker.oscog-nice.2715], Win10 Pro Sorry for not being more explicit before :) Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Mon Mar 1 10:49:53 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 1 Mar 2021 11:49:53 +0100 Subject: [squeak-dev] The Trunk: Kernel-codefrau.1374.mcz In-Reply-To: <1614595615096-0.post@n4.nabble.com> References: <1614592509436-0.post@n4.nabble.com> <1614595615096-0.post@n4.nabble.com> Message-ID: Hi Jaromir, works on Update 20242. Try updating your image. :-) Best, Marcel Am 01.03.2021 11:47:04 schrieb Jaromir Matas : Hi, I just did thisContext explore and noticed the difference... Prior (Kernel-eem.1373) it shows this: I'm on Squeak6.0alpha-20182-64bit, VM [CoInterpreterPrimitives VMMaker.oscog-nice.2715], Win10 Pro Sorry for not being more explicit before :) Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Mon Mar 1 11:21:51 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 1 Mar 2021 11:21:51 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1728.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1728.mcz ==================== Summary ==================== Name: Morphic-mt.1728 Author: mt Time: 1 March 2021, 12:21:45.616905 pm UUID: 9034e981-d83b-c344-a079-e9eb55c8115f Ancestors: Morphic-mt.1727 Increases robustness during layout computation. Similar to WorldState >> #displayWorldSafely:. Here, faulty layout policies will be disabled to keep the environment responsive. Note that you can try breaking #doLayoutIn: and then take a look at all those #fullBounds sends. (After reverting the last change via the emergency evaluator, of course.) =============== Diff against Morphic-mt.1727 =============== Item was changed: ----- Method: Morph>>adjustLayoutBounds (in category 'layout') ----- adjustLayoutBounds "Adjust the receivers bounds depending on the resizing strategy imposed" | hFit vFit box sbox myExtent myOrigin myBox | hFit := self hResizing. vFit := self vResizing. (hFit == #shrinkWrap or:[vFit == #shrinkWrap]) ifFalse:[^self]. "not needed" (self cellSpacing == #none and: [self listSpacing == #none]) ifFalse: [ self flag: #todo. "mt: Find a way to make cell sizes accessible from here." + self cellSpacing: #none; listSpacing: #none. self notify: 'It is not possible to shrink-wrap around submorphs when the layout policy reserves extra cell space. At this point, we have no access to that extra cell space and we do not know whether the submorph did make use of that extra space. So, shrink-wrapping could make the bounds very unstable.\\Please either reset #cellSpacing and #listSpacing - or change the resizing strategy to #rigid or #spaceFill.' withCRs. ^ self]. box := self layoutBounds. sbox := self submorphBoundsForShrinkWrap outsetBy: self cellInset. myExtent := box extent. myOrigin := box origin. hFit == #shrinkWrap ifTrue:[ myExtent := sbox extent x @ myExtent y. myOrigin := sbox origin x @ myOrigin y]. vFit == #shrinkWrap ifTrue:[ myExtent := myExtent x @ sbox extent y. myOrigin := myOrigin x @ sbox origin y]. "Make sure we don't get smaller than minWidth/minHeight" myExtent x < self minWidth ifTrue:[ myExtent := (myExtent x max: (self minWidth - self bounds width + self layoutBounds width)) @ myExtent y]. myExtent y < self minHeight ifTrue:[ myExtent := myExtent x @ (myExtent y max: (self minHeight - self bounds height + self layoutBounds height))]. myBox := myOrigin extent: myExtent. self setLayoutBoundsFromLayout: myBox.! Item was changed: ----- Method: Morph>>buildDebugMenu: (in category 'debug and other') ----- buildDebugMenu: aHand "Answer a debugging menu for the receiver. The hand argument is seemingly historical and plays no role presently" | aMenu aPlayer | aMenu := MenuMorph new defaultTarget: self. aMenu addStayUpItem. (self hasProperty: #errorOnDraw) ifTrue: [aMenu add: 'start drawing again' translated action: #resumeAfterDrawError. aMenu addLine]. (self hasProperty: #errorOnStep) ifTrue: [aMenu add: 'start stepping again' translated action: #resumeAfterStepError. aMenu addLine]. + (self hasProperty: #errorOnLayout) ifTrue: + [aMenu add: 'start layouting again' translated action: #resumeAfterLayoutError. + aMenu addLine]. aMenu add: 'inspect morph' translated action: #inspectInMorphic:. aMenu add: 'inspect owner chain' translated action: #inspectOwnerChain. Smalltalk isMorphic ifFalse: [aMenu add: 'inspect morph (in MVC)' translated action: #inspect]. self isMorphicModel ifTrue: [aMenu add: 'inspect model' translated target: self model action: #inspect; add: 'explore model' translated target: self model action: #explore]. (aPlayer := self player) ifNotNil: [aMenu add: 'inspect player' translated target: aPlayer action: #inspect]. aMenu add: 'explore morph' translated target: self selector: #exploreInMorphic:. aMenu addLine. aPlayer ifNotNil: [ aMenu add: 'viewer for Player' translated target: self player action: #beViewed. aMenu balloonTextForLastItem: 'Opens a viewer on my Player -- this is the same thing you get if you click on the cyan "View" halo handle' translated ]. aMenu add: 'viewer for Morph' translated target: self action: #viewMorphDirectly. aMenu balloonTextForLastItem: 'Opens a Viewer on this Morph, rather than on its Player' translated. aMenu addLine. aPlayer ifNotNil: [aPlayer class isUniClass ifTrue: [ aMenu add: 'browse player class' translated target: aPlayer selector: #haveFullProtocolBrowsedShowingSelector: argumentList: #(nil)]]. aMenu add: 'browse morph class' translated target: self selector: #browseHierarchy. (self isMorphicModel) ifTrue: [aMenu add: 'browse model class' target: self model selector: #browseHierarchy]. aMenu addLine. self addViewingItemsTo: aMenu. aMenu add: 'make own subclass' translated action: #subclassMorph; add: 'save morph in file' translated action: #saveOnFile; addLine; add: 'call #tempCommand' translated action: #tempCommand; add: 'define #tempCommand' translated action: #defineTempCommand; addLine; add: 'control-menu...' translated target: self selector: #invokeMetaMenu:; add: 'edit balloon help' translated action: #editBalloonHelpText. ^ aMenu! Item was added: + ----- Method: Morph>>doLayout (in category 'layout') ----- + doLayout + + self doLayoutIn: self layoutBounds.! Item was added: + ----- Method: Morph>>doLayoutSafely (in category 'layout') ----- + doLayoutSafely + "Also see #resumeAfterLayoutError." + + [fullBounds] whileNil: [ + [self doLayout] on: Error, Halt, Warning do: [:error | + + | errorMorph | + (error signalerContext + findContextSuchThat: [:context | + context receiver isMorph and: [context receiver layoutPolicy notNil]]) + ifNil: [^ Project current primitiveError: error description] + ifNotNil: [:errorContext | errorMorph := errorContext receiver]. + errorMorph + instVarNamed: #fullBounds + put: (errorMorph instVarNamed: #bounds). + (Warning handles: error) ifFalse: [ + "Disable the policy unless it is a warning, which should be secured where signaled to ease debugging." + errorMorph + setProperty: #errorOnLayout toValue: errorMorph layoutPolicy; + setProperty: #layoutPolicy toValue: nil. "Avoid #layoutChanged!!"]. + + ToolSet debugException: error]].! Item was changed: ----- Method: Morph>>fullBounds (in category 'layout') ----- fullBounds + "Return the bounding box of the receiver and all its children. Recompute the layout if necessary. See #layoutChanged." + + ^ fullBounds ifNil: [self doLayoutSafely. fullBounds]! - "Return the bounding box of the receiver and all its children. Recompute the layout if necessary." - fullBounds ifNotNil:[^fullBounds]. - "Errors at this point can be critical so make sure we catch 'em all right" - [self doLayoutIn: self layoutBounds] on: Error, Warning, Halt do:[:ex| - "This should do it unless you don't screw up the bounds" - fullBounds := bounds. - ex pass]. - ^fullBounds! Item was added: + ----- Method: Morph>>resumeAfterLayoutError (in category 'debug and other') ----- + resumeAfterLayoutError + "Resume layouting after an error has occured." + + self layoutPolicy: (self valueOfProperty: #errorOnLayout ifAbsent: [^ self]). + self removeProperty:#errorOnLayout.! Item was changed: ----- Method: MorphicDebugger class>>openOn:context:label:contents:fullView: (in category 'opening') ----- openOn: processToDebug context: context label: title contents: contentsStringOrNil fullView: full | debugger uiBlock | debugger := self new process: processToDebug context: context; errorWasInUIProcess: (Project current spawnNewProcessIfThisIsUI: processToDebug). uiBlock := [ full ifTrue: [debugger openFullNoSuspendLabel: title] ifFalse: [debugger openNotifierNoSuspendContents: contentsStringOrNil label: title]. + "Try layouting the debugger tool at least once to avoid freeze." + debugger topView ifNotNil: [:window | + "There are way too many #fullBounds sends. Layout errors might already have happened." + window allMorphsDo: [:m | (m hasProperty: #errorOnLayout) ifTrue: [self error: 'Layout error']]. + window world doLayout. "Not safely!!"]. "Try drawing the debugger tool at least once to avoid freeze." debugger topView ifNotNil: [:window | window world displayWorld. "Not safely!!"]. ]. "Schedule debugging in a deferred UI message if necessary. Note that only the ui process should execute ui code." (Project current uiProcess isActiveProcess not or: [processToDebug isActiveProcess]) ifTrue: [Project current addDeferredUIMessage: uiBlock] ifFalse: uiBlock. processToDebug suspend. "Get here only if active process is not the process-to-debug. So in tests, use a helper process if you want to access this return value." ^ debugger! From lists at fniephaus.com Mon Mar 1 13:13:18 2021 From: lists at fniephaus.com (Fabio Niephaus) Date: Mon, 1 Mar 2021 14:13:18 +0100 Subject: [squeak-dev] Squeak-related Talks this Friday In-Reply-To: References: <1614357289-a56b358b68c1860af9c7f67f3774a427@pckswarms.ch> Message-ID: Hi all, Yes, the talks were recorded! We'll publish and share them with you once we have the actual files. Best, Fabio On Fri, Feb 26, 2021 at 5:42 PM Liam Proven wrote: > > On Fri, 26 Feb 2021 at 17:35, Bruce O'Neel wrote: > > > Is it possible that the talks were recorded, and, if so that we can see them? > > Whoops. What he said! I only saw the announcement now. :-( > > -- > Liam Proven – Profile: https://about.me/liamproven > Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com > Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven > UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 > From commits at source.squeak.org Mon Mar 1 16:42:14 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 1 Mar 2021 16:42:14 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1729.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1729.mcz ==================== Summary ==================== Name: Morphic-mt.1729 Author: mt Time: 1 March 2021, 5:42:08.604934 pm UUID: 5bc3cc16-c4ce-bb45-921d-e5ba198cf436 Ancestors: Morphic-mt.1728 Fixes submorph insertion order for layer-specific add-all interface. =============== Diff against Morphic-mt.1728 =============== Item was changed: ----- Method: Morph>>addAllMorphsFrontInLayers: (in category 'submorphs - layers') ----- addAllMorphsFrontInLayers: morphs + morphs reverseDo: [:morph | self addMorphFrontInLayer: morph].! - morphs do: [:morph | self addMorphFrontInLayer: morph].! From commits at source.squeak.org Mon Mar 1 16:59:13 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 1 Mar 2021 16:59:13 0000 Subject: [squeak-dev] The Trunk: MorphicTests-mt.71.mcz Message-ID: Marcel Taeumel uploaded a new version of MorphicTests to project The Trunk: http://source.squeak.org/trunk/MorphicTests-mt.71.mcz ==================== Summary ==================== Name: MorphicTests-mt.71 Author: mt Time: 1 March 2021, 5:59:12.350934 pm UUID: 848fe7e9-51bf-1544-8c4f-ac96274f1f5f Ancestors: MorphicTests-mt.70 Adds tests about layer-specific add-all interface. =============== Diff against MorphicTests-mt.70 =============== Item was changed: ----- Method: MorphTest>>createAndAddMorphs: (in category 'support') ----- createAndAddMorphs: someNames + (self createMorphs: someNames) do: [:newMorph | - (self createMorphs: #(a b)) do: [:newMorph | morph addMorphBack: newMorph].! Item was added: + ----- Method: MorphTest>>createMorphs:inLayers: (in category 'support') ----- + createMorphs: names inLayers: layerNumbers + + ^ names with: layerNumbers collect: [:name :layer | + Morph new name: name; morphicLayerNumber: layer; yourself]! Item was added: + ----- Method: MorphTest>>test13AddAllMorphsInLayers (in category 'tests - submorphs - layers') ----- + test13AddAllMorphsInLayers + + morph addAllMorphsInLayers: (self createMorphs: #(a b) inLayers: #(5 4)). + self assert: #(b a) equals: self getSubmorphNames. + + morph addAllMorphsInLayers: (self createMorphs: #(x y z) inLayers: #(3 3 5)). + self assert: #(x y b a z) equals: self getSubmorphNames.! Item was added: + ----- Method: MorphTest>>test14AddAllMorphsFrontInLayers (in category 'tests - submorphs - layers') ----- + test14AddAllMorphsFrontInLayers + + morph addAllMorphsFrontInLayers: (self createMorphs: #(a b) inLayers: #(5 4)). + self assert: #(b a) equals: self getSubmorphNames. + + morph addAllMorphsFrontInLayers: (self createMorphs: #(x y z) inLayers: #(3 3 5)). + self assert: #(x y b z a) equals: self getSubmorphNames.! Item was added: + ----- Method: MorphTest>>test15AddAllMorphsBackInLayers (in category 'tests - submorphs - layers') ----- + test15AddAllMorphsBackInLayers + + morph addAllMorphsBackInLayers: (self createMorphs: #(a b) inLayers: #(5 4)). + self assert: #(b a) equals: self getSubmorphNames. + + morph addAllMorphsBackInLayers: (self createMorphs: #(x y z) inLayers: #(3 3 5)). + self assert: #(x y b a z) equals: self getSubmorphNames.! From m at jaromir.net Mon Mar 1 17:17:37 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 1 Mar 2021 11:17:37 -0600 (CST) Subject: [squeak-dev] The Trunk: Kernel-codefrau.1374.mcz In-Reply-To: References: <1614592509436-0.post@n4.nabble.com> <1614595615096-0.post@n4.nabble.com> Message-ID: <1614619057446-0.post@n4.nabble.com> Thanks! Apologies for false alarm. Regards, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Mon Mar 1 23:41:25 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 1 Mar 2021 17:41:25 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1376.mcz In-Reply-To: References: <1614539317095-0.post@n4.nabble.com> Message-ID: <1614642085549-0.post@n4.nabble.com> Hi Eliot, > > I like this. But isn't this a little bit better? > > isTerminated > "Answer if the receiver is terminated, or at least terminating." > self isActiveProcess ifTrue: [^ false]. > ^suspendedContext isNil > or: ["If the suspendedContext is the bottomContext and the pc is at > the endPC, > then there is nothing more to do." > suspendedContext isBottomContext > and: [suspendedContext pc >= suspendedContext endPC > or: [suspendedContext closure isNil > and: [suspendedContext methodClass == Process > and: [suspendedContext selector == > #terminate]]]]] delightful! Thanks ;) Just for my curiosity - would this be considered a bad style (or is a math like logical expression better): isTerminated "Answer if the receiver is terminated, or at least terminating. If the suspendedContext is the bottomContext and the pc is at the endPC, then there is nothing more to do. If an active process is terminated, it means it was suspended inside the #terminate method leaving pc < endPC, so it needs to be caught separately" self isActiveProcess ifTrue: [^false]. suspendedContext ifNil: [^true]. suspendedContext isBottomContext ifFalse: [^false]. suspendedContext pc >= suspendedContext endPC ifTrue: [^true]. ^suspendedContext closure isNil and: [suspendedContext methodClass == Process and: [suspendedContext selector == #terminate]] > I'm also tempted to state in a comment why being in other than a block in > Process>>#terminate implies the methods is essentially done terminating. > And there in lies the rub, to quote Shakespeare. My attempted explanation in the comment above but I'm not sure... > Would a hack like adding a first temporary in Process>>#terminate called > e.g. terminationStatus and having Process>>terminate assign to it when > termination is essentially complete be better? > > e.g. > > isTerminated > "Answer if the receiver is terminated, or at least terminating." > self isActiveProcess ifTrue: [^ false]. > ^suspendedContext isNil > or: ["If the suspendedContext is the bottomContext and the pc is at > the endPC, > then there is nothing more to do." > suspendedContext isBottomContext > and: [suspendedContext pc >= suspendedContext endPC > or: [suspendedContext closure isNil > and: [suspendedContext methodClass == Process > and: [suspendedContext selector == #terminate > and: [(suspendedContext localAt: 1) == > #terminated]]]]]] > I tried to figure out whether you just wanted to detect termination status as early as possible or also something else... I guess the condition should be (not tested): isTerminated "Answer if the receiver is terminated, or at least terminating." self isActiveProcess ifTrue: [^ false]. ^suspendedContext isNil or: ["If the suspendedContext is the bottomContext and the pc is at the endPC, then there is nothing more to do." suspendedContext isBottomContext and: [suspendedContext pc >= suspendedContext endPC or: [(suspendedContext localAt: 1) == #terminated]]] ... because `suspendedContext closure isNil` etc. only catches terminating a suspended process. So to also cover terminating the active process we can, I guess, safely remove this condition. I'm not sure though about the localAt: 1 - what if other non-terminating process had it with the same #terminated - is it ok? Also - #isSuspended suffers with the same problem as #isTerminated; I'll take a look at it next. Thanks, Best regards ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From lproven at gmail.com Tue Mar 2 01:30:10 2021 From: lproven at gmail.com (Liam Proven) Date: Tue, 2 Mar 2021 02:30:10 +0100 Subject: [squeak-dev] [RE] seL4 Microkernel: How small can the shim be? In-Reply-To: References: Message-ID: On Sun, 28 Feb 2021 at 17:16, wrote: > > I think you have specified a null set. I know. It sounds unlikely. However, Oberon is real, it has users, there are native versions for x86 and RISC5 (note, *not* RISC-V) and hosted versions on Windows, macOS and both x86 & ARM Linux (and formerly for DOS). > > Alan Kay said: "The best way to predict the future is to invent it." > > You have described the world you want to move into. I tried to, certainly. > My only suggestion here is to look at OSs which are easily ported. I > would look at RISC-V because the kind of solution you are looking for > will probably appear there first. TBH I am not convinced it's mature enough just yet. I could be wrong. > Within "type-strict", you might consider a Rust or Haskell oSs. I am aware of some but they do seem _very_ niche. > [I > think Smalltalk is "type-safe", every object knows its class and trying > to access element 41 of a 10 element array gives DNU, but I suspect this > is not your definition]. Close enough for government work. :-) > For small, FreeRTOS and PharOS > (https://sourceforge.net/projects/rtospharos/) look interesting. They do indeed. I will do some more reading. > From Wikipedia entry on RISC-V: [...] > Note also OSDev.org. Indeed. There is an experimental RISC-V implementation: https://github.com/solbjorg/oberon-riscv Of course, this is doomed to lead to horrible confusion, since Oberon's "native" platform is Professor Wirth's own RISC5 CPU, now implemented on several FPGA devices. https://people.inf.ethz.ch/wirth/ProjectOberon/RISC5.Update.pdf I have heard a rumour it was done partly because Prof W was irked that the main extant native versions were on x86. RISC-V (pronounced "risk five" as opposed to RISC5 (pronounced "risk five", I think, or I suppose "risk funf")? What could possibly go wrong? -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From m at jaromir.net Tue Mar 2 08:06:58 2021 From: m at jaromir.net (Jaromir Matas) Date: Tue, 2 Mar 2021 02:06:58 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1376.mcz In-Reply-To: <1614642085549-0.post@n4.nabble.com> References: <1614539317095-0.post@n4.nabble.com> <1614642085549-0.post@n4.nabble.com> Message-ID: <1614672418445-0.post@n4.nabble.com> Hi Eliot, To clarify some confusion in my last message I tested your idea: it works as expected for an active process termination. In case of suspended process termination the suspendedContext is actually not the one of Process>>terminate so it doesn't do anything except the debugger doesn't like it and gets stuck before sending #bottomContext following the terminationStatus assignment (weird). I also had to change the isTerminated condition because the context becomes bottom one step after assigning the terminationStatus (all tests are green but...): isTerminated "Answer if the receiver is terminated, or at least terminating. If an active process has terminated, it means it was suspended inside the #terminate method and this situation needs to be caught separately. If the suspendedContext is the bottomContext and the pc is at the endPC, then there is nothing more to do." self isActiveProcess ifTrue: [^false]. ^suspendedContext isNil or: [suspendedContext pc isNil] or: [suspendedContext methodClass == Process and: [suspendedContext selector == #terminate and: [(suspendedContext tempAt: 1) == #terminated]]] or: [suspendedContext isBottomContext and: [suspendedContext pc >= suspendedContext endPC]] Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Tue Mar 2 09:03:02 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 2 Mar 2021 10:03:02 +0100 Subject: [squeak-dev] What about "self currentProject"? Message-ID: Hi all! After typing "Project current" for the n-th time, I was wondering, whether "self currentProject" could be a nice little idiom for the Squeak environment.  We had several thoughts on this matter: http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072 [http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072] http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html [http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html] 1. Object >> #currentProject would be a *System extension in Object to not be dependent on Morphic. 2.  "Project current world" could be replaced with "self currentProject world" (generic) or "self currentWorld" (specific to Morphic). 3. "Project uiManager" could be replaced with "self currentProject uiManager". 4. "Project current addDeferredUIMessage:" could be replaced with "self currentProject addDeferredUIMessage:". So, we wouldn't have so many class references to "Project" in the code. It kind of reminds me about some of Newspeak's design goals. :-) What do you think? Best, Marcel -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 2 10:01:45 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 10:01:45 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1730.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1730.mcz ==================== Summary ==================== Name: Morphic-mt.1730 Author: mt Time: 2 March 2021, 11:01:40.072687 am UUID: 5fa729ff-1ebb-3a4e-8283-f88485971bd6 Ancestors: Morphic-mt.1729 A fix and a tweak. (Note that it is interesting that damage-recording-based drawing via #changed and deferred layout computation via #layoutChanged are in conflict with each other. Also see #privateInvalidateMorph: and its senders.) =============== Diff against Morphic-mt.1729 =============== Item was changed: ----- Method: Morph>>position: (in category 'geometry') ----- position: aPoint "Change the position of this morph, which is the top left corner of its bounds." | delta box | delta := (aPoint - self bounds topLeft) rounded. "Skip drawing and layout updates for null changes." (delta x = 0 and: [delta y = 0]) ifTrue: [^ self]. "Optimize drawing. Record one damage rectangle for short distance and two damage rectangles for large distances." + box := fullBounds ifNil: [self outerBounds]. "Avoid premature layout computation. Like in #extent: and #changed." - box := self fullBounds. (delta dotProduct: delta) > 100 "More than 10 pixels?" ifTrue: [self invalidRect: box; invalidRect: (box translateBy: delta)] ifFalse: [self invalidRect: (box merge: (box translateBy: delta))]. "Move this morph and *all* of its submorphs." self privateFullMoveBy: delta. "For all known layout policies, my layout and the layout of my children is fine. Only the layout of my owner might be affected. So, tell about it." self owner ifNotNil: [:o | self flag: #todo. "mt: Maybe we can save a lot of effort and troubles by only calling #layoutChanged if the owner has a layout policy installed? Take the thumbs of scroll-bars as an example..." o layoutChanged].! Item was changed: ----- Method: Morph>>setToAdhereToEdge: (in category 'menus') ----- setToAdhereToEdge: anEdge anEdge ifNil: [^ self]. anEdge == #none ifTrue: [^ self removeProperty: #edgeToAdhereTo]. self setProperty: #edgeToAdhereTo toValue: anEdge. + self layoutChanged. ! From commits at source.squeak.org Tue Mar 2 10:03:23 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 10:03:23 0000 Subject: [squeak-dev] The Trunk: MorphicTests-mt.72.mcz Message-ID: Marcel Taeumel uploaded a new version of MorphicTests to project The Trunk: http://source.squeak.org/trunk/MorphicTests-mt.72.mcz ==================== Summary ==================== Name: MorphicTests-mt.72 Author: mt Time: 2 March 2021, 11:03:22.265687 am UUID: b86bc3c1-fdde-7343-9628-073d9dd73d70 Ancestors: MorphicTests-mt.71 More tests for the new grid layout. =============== Diff against MorphicTests-mt.71 =============== Item was changed: ----- Method: GridLayoutTest>>test01Position (in category 'tests') ----- test01Position + | m o | - | m | m := self addMorph. + o := container position. { 0 at 0 . 0 at 0 . 9 at 9 . 0 at 0 . 10 at 10 . 20 at 20 . 25 at 25 . 20 at 20 } pairsDo: [:newPosition :expectedGrid | + m position: newPosition + o. - m position: newPosition. container fullBounds. + self assert: expectedGrid + o equals: m position].! - self assert: expectedGrid equals: m position].! Item was added: + ----- Method: GridLayoutTest>>test05SnapToEdge (in category 'tests') ----- + test05SnapToEdge + "The grid should be ignored for morphs that snap to their owner's edges." + + | m | + m := Morph new color: Color random; extent: 10 at 10; yourself. + container addMorph: m. + + "1) Manual snap-to-edge will not work." + m position: 0@(100 - 10). + container fullBounds. + self assert: 0 at 100 equals: m position. + + "2) Use snap-to-edge property." + m setToAdhereToEdge: #bottom. + container fullBounds. + self assert: 0@(100 - 10) equals: m position.! Item was added: + ----- Method: GridLayoutTest>>test06Origin (in category 'tests') ----- + test06Origin + "The grid's origin should be relative to its morph's position so that the morph can be moved around without the grid changing." + + container position: 0 at 0. + container removeAllMorphs. + self test01Position. + + container position: 10 at 10. + container removeAllMorphs. + self test01Position.! From commits at source.squeak.org Tue Mar 2 10:44:27 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 10:44:27 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1731.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1731.mcz ==================== Summary ==================== Name: Morphic-mt.1731 Author: mt Time: 2 March 2021, 11:44:21.476687 am UUID: d06129c7-0def-1645-9066-c8a5720bf5d2 Ancestors: Morphic-mt.1730 Adds the possibility to handle #ownerChanged through composition (instead of subclassing/overwriting). Note that #cull: also works with symbols and message sends, not just blocks. :-) Got inspired by #eventHandler and how #mouseDown: (etc.) is implemented in Morph. Use it to extract Etoys-specific background morph and grid. =============== Diff against Morphic-mt.1730 =============== Item was changed: + ----- Method: Morph>>ownerChanged (in category 'layout') ----- - ----- Method: Morph>>ownerChanged (in category 'change reporting') ----- ownerChanged "This morph's owner has changed its geometry and is about to update its layout. This is a simple layout hook to update this morph's geometry according to its owner. For more advanced strategies, use a LayoutPolicy with some LayoutProperties. See #layoutPolicy: and maybe also #doLayoutIn:." + self snapToEdgeIfAppropriate. + + self ownerChangedHandler + ifNotNil: [:handler | handler cull: self].! - self snapToEdgeIfAppropriate.! Item was added: + ----- Method: Morph>>ownerChangedHandler (in category 'layout') ----- + ownerChangedHandler + + ^ self valueOfProperty: #ownerChangedHandler! Item was added: + ----- Method: Morph>>ownerChangedHandler: (in category 'layout') ----- + ownerChangedHandler: aHandler + + self + setProperty: #ownerChangedHandler + toValue: aHandler. + + self layoutChanged.! Item was changed: ----- Method: MorphicProject class>>applyUserInterfaceTheme (in category 'preferences') ----- applyUserInterfaceTheme self current addDeferredUIMessage: [ "After all immediate changes where applied, we can reset to values that match the current world configuration:" self worldGridOrigin: nil. self worldGridModulus: nil. + self worldGridEnabled - self current world griddingOn ifTrue: [self current world firstHand turnOnGridding]].! Item was changed: ----- Method: MorphicProject class>>worldGridEnabled (in category 'preferences') ----- worldGridEnabled + + | world | + world := self current world. + ^ self current isMorphic and: [world layoutPolicy notNil and: [world layoutPolicy isGridLayout]]! - ^ self current isMorphic and: [self current world griddingOn]! Item was changed: ----- Method: MorphicProject class>>worldGridEnabled: (in category 'preferences') ----- worldGridEnabled: aBooleanOrNil + (aBooleanOrNil ifNil: [false]) + ifTrue: [self current world layoutPolicy: GridLayout new] + ifFalse: [self current world layoutPolicy: nil]. - (aBooleanOrNil ifNil: [false]) = self current world griddingOn - ifFalse: [self current world griddingOnOff]. "Auto-configure origin and modulus to match world properties." self worldGridOrigin: nil. self worldGridModulus: nil. "Snap to grid when dragging something." + self worldGridEnabled - self current world griddingOn ifTrue: [self current world firstHand turnOnGridding] ifFalse: [self current world firstHand turnOffGridding].! Item was changed: BorderedMorph subclass: #PasteUpMorph + instanceVariableNames: 'presenter model cursor padding turtleTrailsForm turtlePen lastTurtlePositions isPartsBin indicateCursor wantsMouseOverHalos worldState' - instanceVariableNames: 'presenter model cursor padding backgroundMorph turtleTrailsForm turtlePen lastTurtlePositions isPartsBin indicateCursor wantsMouseOverHalos worldState' classVariableNames: 'GlobalCommandKeysEnabled WindowEventHandler' poolDictionaries: '' category: 'Morphic-Worlds'! !PasteUpMorph commentStamp: '' prior: 0! A morph whose submorphs comprise a paste-up of rectangular subparts which "show through". Anything called a 'Playfield' is a PasteUpMorph. Facilities commonly needed on pages of graphical presentations and on simulation playfields, such as the painting of new objects, turtle trails, gradient fills, background paintings, parts-bin behavior, collision-detection, etc., are (or will be) provided. A World, the entire Smalltalk screen, is a PasteUpMorph. A World responds true to isWorld. Morph subclasses that have specialized menus (BookMorph) build them in the message addBookMenuItemsTo:hand:. A PasteUpMorph that is a world, builds its menu in HandMorph buildWorldMenu. presenter A Presenter in charge of stopButton stepButton and goButton, mouseOverHalosEnabled soundsEnabled fenceEnabled coloredTilesEnabled. model cursor ?? padding ?? backgroundMorph A Form that covers the background. turtleTrailsForm Moving submorphs may leave trails on this form. turtlePen Draws the trails. lastTurtlePositions A Dictionary of (aPlayer -> aPoint) so turtle trails can be drawn only once each step cycle. The point is the start of the current stroke. isPartsBin If true, every object dragged out is copied. autoLineLayout ?? indicateCursor ?? resizeToFit ?? wantsMouseOverHalos If true, simply moving the cursor over a submorph brings up its halo. worldState If I am also a World, keeps the hands, damageRecorder, stepList etc. griddingOn If true, submorphs are on a grid ! Item was changed: ----- Method: PasteUpMorph>>drawOn: (in category 'drawing') ----- drawOn: aCanvas "Draw in order: - background color - - grid, if any - - background sketch, if any - Update and draw the turtleTrails form. See the comment in updateTrailsForm. - cursor box if any Later (in drawSubmorphsOn:) I will skip drawing the background sketch." "draw background fill" super drawOn: aCanvas. - "draw grid" - (self griddingOn and: [self gridVisible]) - ifTrue: - [aCanvas fillRectangle: self bounds - fillStyle: (self - gridFormOrigin: self gridOrigin - grid: self gridModulus - background: nil - line: Color lightGray)]. - - "draw background sketch." - backgroundMorph ifNotNil: [ - self clipSubmorphs ifTrue: [ - aCanvas clipBy: self clippingBounds - during: [ :canvas | canvas fullDrawMorph: backgroundMorph ]] - ifFalse: [ aCanvas fullDrawMorph: backgroundMorph ]]. - "draw turtle trails" (lastTurtlePositions isNil or: [lastTurtlePositions isEmpty]) ifFalse:[ self updateTrailsForm. ]. turtleTrailsForm ifNotNil: [aCanvas paintImage: turtleTrailsForm at: self position]. "draw cursor" (submorphs notEmpty and: [self indicateCursor]) ifTrue: [aCanvas frameRectangle: self selectedRect width: 2 color: Color black]! Item was removed: - ----- Method: PasteUpMorph>>drawSubmorphsOn: (in category 'painting') ----- - drawSubmorphsOn: aCanvas - "Display submorphs back to front, but skip my background sketch." - - | drawBlock | - submorphs isEmpty ifTrue: [^self]. - drawBlock := [:canvas | submorphs reverseDo: [:m | m ~~ backgroundMorph ifTrue: [ canvas fullDrawMorph: m ]]]. - self clipSubmorphs - ifTrue: [aCanvas clipBy: self clippingBounds during: drawBlock] - ifFalse: [drawBlock value: aCanvas]! Item was removed: - ----- Method: PasteUpMorph>>gridVisible (in category 'gridding') ----- - gridVisible - - ^ self hasProperty: #gridVisible! Item was removed: - ----- Method: PasteUpMorph>>gridVisibleOnOff (in category 'gridding') ----- - gridVisibleOnOff - - self setProperty: #gridVisible toValue: self gridVisible not. - self changed! Item was removed: - ----- Method: PasteUpMorph>>gridVisibleString (in category 'gridding') ----- - gridVisibleString - "Answer a string to be used in a menu offering the opportunity - to show or hide the grid" - ^ (self gridVisible - ifTrue: [''] - ifFalse: ['']) - , 'grid visible when gridding' translated! Item was removed: - ----- Method: PasteUpMorph>>griddingOn (in category 'gridding') ----- - griddingOn - - ^ self layoutPolicy notNil and: [self layoutPolicy isGridLayout]! Item was removed: - ----- Method: PasteUpMorph>>griddingOnOff (in category 'gridding') ----- - griddingOnOff - "Change grid layout. Consider the #clearArea to ignore docking bars and other adhereing morphs." - - self layoutPolicy: (self griddingOn ifFalse: [GridLayout new]).! Item was removed: - ----- Method: PasteUpMorph>>griddingString (in category 'gridding') ----- - griddingString - "Answer a string to use in a menu offering the user the - opportunity to start or stop using gridding" - ^ (self griddingOn - ifTrue: [''] - ifFalse: ['']) - , 'use gridding' translated! Item was removed: - ----- Method: PasteUpMorph>>privateRemoveMorph: (in category 'private') ----- - privateRemoveMorph: aMorph - backgroundMorph == aMorph ifTrue: [ backgroundMorph := nil ]. - ^super privateRemoveMorph: aMorph. - ! Item was removed: - ----- Method: PasteUpMorph>>setGridSpec (in category 'gridding') ----- - setGridSpec - "Gridding rectangle provides origin and modulus" - | response result | - response := UIManager default - request: 'New grid origin (usually 0 at 0):' translated - initialAnswer: self gridOrigin printString. - response isEmpty ifTrue: [^ self]. - result := [Compiler evaluate: response] ifError: [^ self]. - (result isPoint and: [(result >= (0 at 0))]) - ifTrue: [self gridOrigin: result] - ifFalse: [self inform: ('Must be a Point with coordinates (for example 10 at 10)' translated )]. - - response := UIManager default - request: 'New grid spacing:' translated - initialAnswer: self gridModulus printString. - response isEmpty ifTrue: [^ self]. - result := [Compiler evaluate: response] ifError: [^ self]. - (result isPoint and: [(result > (0 at 0)) ]) - ifTrue: [self gridModulus: result] - ifFalse: [self inform: ('Must be a Point with coordinates (for example 10 at 10)' translated )]. - - ! From commits at source.squeak.org Tue Mar 2 10:45:42 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 10:45:42 0000 Subject: [squeak-dev] The Trunk: EToys-mt.429.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.429.mcz ==================== Summary ==================== Name: EToys-mt.429 Author: mt Time: 2 March 2021, 11:45:35.238687 am UUID: ef67f837-252c-6b4d-a9ff-b543b854da2a Ancestors: EToys-mt.428 Complements Morphic-mt.1731 =============== Diff against EToys-mt.428 =============== Item was changed: ----- Method: PasteUpMorph>>backgroundForm (in category '*Etoys-playfield') ----- backgroundForm ^ self backgroundSketch ifNil: [Form extent: self extent depth: Display depth] + ifNotNil: [:sketch | sketch form]! - ifNotNil: [backgroundMorph form]! Item was added: + ----- Method: PasteUpMorph>>backgroundGridMorph (in category '*Etoys-playfield-gridding') ----- + backgroundGridMorph + + ^ self valueOfProperty: #backgroundGridMorph! Item was added: + ----- Method: PasteUpMorph>>backgroundGridMorph: (in category '*Etoys-playfield-gridding') ----- + backgroundGridMorph: aMorph + + self setProperty: #backgroundGridMorph toValue: aMorph.! Item was added: + ----- Method: PasteUpMorph>>backgroundMorph (in category '*Etoys-playfield') ----- + backgroundMorph + + ^ self valueOfProperty: #backgroundMorph! Item was added: + ----- Method: PasteUpMorph>>backgroundMorph: (in category '*Etoys-playfield') ----- + backgroundMorph: aMorph + + self setProperty: #backgroundMorph toValue: aMorph.! Item was changed: ----- Method: PasteUpMorph>>backgroundSketch (in category '*Etoys-playfield') ----- backgroundSketch + self backgroundMorph ifNil: [^ nil]. + self backgroundMorph owner == self ifFalse: + [self backgroundMorph: nil]. "has been deleted" + ^ self backgroundMorph! - backgroundMorph ifNil: [^ nil]. - backgroundMorph owner == self ifFalse: - [backgroundMorph := nil]. "has been deleted" - ^ backgroundMorph! Item was changed: ----- Method: PasteUpMorph>>backgroundSketch: (in category '*Etoys-playfield') ----- backgroundSketch: aSketchMorphOrNil "Set the receiver's background graphic as indicated. If nil is supplied, remove any existing background graphic. In any case, delete any preexisting background graphic." + self backgroundMorph ifNotNil: [self backgroundMorph delete]. "replacing old background" - backgroundMorph ifNotNil: [backgroundMorph delete]. "replacing old background" + aSketchMorphOrNil ifNil: [self backgroundMorph: nil. ^ self]. - aSketchMorphOrNil ifNil: [backgroundMorph := nil. ^ self]. + self backgroundMorph: (StickySketchMorph new form: aSketchMorphOrNil form). + self backgroundMorph position: aSketchMorphOrNil position. + self addMorphBack: self backgroundMorph. - backgroundMorph := StickySketchMorph new form: aSketchMorphOrNil form. - backgroundMorph position: aSketchMorphOrNil position. - self addMorphBack: backgroundMorph. aSketchMorphOrNil delete. + self backgroundMorph lock. + self backgroundMorph disableLayout: true. + self backgroundMorph setProperty: #shared toValue: true. + self backgroundMorph morphicLayerNumber: self class backmostLayer. + ^ self backgroundMorph - backgroundMorph lock. - backgroundMorph setProperty: #shared toValue: true. - ^ backgroundMorph ! Item was changed: ----- Method: PasteUpMorph>>deleteBackgroundPainting (in category '*Etoys-playfield') ----- deleteBackgroundPainting + self backgroundMorph - backgroundMorph ifNotNil: + [self backgroundMorph delete. + self backgroundMorph: nil] - [backgroundMorph delete. - backgroundMorph := nil] ifNil: [self inform: 'There is presently no background painting to delete.' translated]! Item was added: + ----- Method: PasteUpMorph>>gridVisible (in category '*Etoys-playfield-gridding') ----- + gridVisible + + ^ self hasProperty: #gridVisible! Item was added: + ----- Method: PasteUpMorph>>gridVisibleOnOff (in category '*Etoys-playfield-gridding') ----- + gridVisibleOnOff + + self setProperty: #gridVisible toValue: self gridVisible not. + + self backgroundGridMorph ifNotNil: [:morph | morph delete]. + + self gridVisible ifFalse: [self backgroundGridMorph: nil. ^ self]. + + self backgroundGridMorph: (Morph new + fillStyle: (self + gridFormOrigin: self gridOrigin grid: self gridModulus + background: nil line: Color lightGray); + lock; + disableLayout: true; "The morphs itself visualizes the origin." + ownerChangedHandler: [:m | m bounds: m owner bounds]; + morphicLayerNumber: self class backmostLayer - 1). + + self addMorph: self backgroundGridMorph.! Item was added: + ----- Method: PasteUpMorph>>gridVisibleString (in category '*Etoys-playfield-gridding') ----- + gridVisibleString + "Answer a string to be used in a menu offering the opportunity + to show or hide the grid" + ^ (self gridVisible + ifTrue: [''] + ifFalse: ['']) + , 'grid visible when gridding' translated! Item was added: + ----- Method: PasteUpMorph>>griddingOn (in category '*Etoys-playfield-gridding') ----- + griddingOn + + ^ self layoutPolicy notNil and: [self layoutPolicy isGridLayout]! Item was added: + ----- Method: PasteUpMorph>>griddingOnOff (in category '*Etoys-playfield-gridding') ----- + griddingOnOff + "Change grid layout. Consider the #clearArea to ignore docking bars and other adhereing morphs." + + self layoutPolicy: (self griddingOn ifFalse: [GridLayout new]).! Item was added: + ----- Method: PasteUpMorph>>griddingString (in category '*Etoys-playfield-gridding') ----- + griddingString + "Answer a string to use in a menu offering the user the + opportunity to start or stop using gridding" + ^ (self griddingOn + ifTrue: [''] + ifFalse: ['']) + , 'use gridding' translated! Item was added: + ----- Method: PasteUpMorph>>setGridSpec (in category '*Etoys-playfield-gridding') ----- + setGridSpec + "Gridding rectangle provides origin and modulus" + | response result | + response := UIManager default + request: 'New grid origin (usually 0 at 0):' translated + initialAnswer: self gridOrigin printString. + response isEmpty ifTrue: [^ self]. + result := [Compiler evaluate: response] ifError: [^ self]. + (result isPoint and: [(result >= (0 at 0))]) + ifTrue: [self gridOrigin: result] + ifFalse: [self inform: ('Must be a Point with coordinates (for example 10 at 10)' translated )]. + + response := UIManager default + request: 'New grid spacing:' translated + initialAnswer: self gridModulus printString. + response isEmpty ifTrue: [^ self]. + result := [Compiler evaluate: response] ifError: [^ self]. + (result isPoint and: [(result > (0 at 0)) ]) + ifTrue: [self gridModulus: result] + ifFalse: [self inform: ('Must be a Point with coordinates (for example 10 at 10)' translated )]. + + ! From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 2 11:59:51 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 2 Mar 2021 05:59:51 -0600 (CST) Subject: [squeak-dev] The Trunk: CollectionsTests-dtl.350.mcz In-Reply-To: References: Message-ID: <1614686391666-0.post@n4.nabble.com> Hi Dave, could there be something wrong with the ancestry of this version? The notification email does not contain any visible diff and when updating my image today, I got an MCEmptyDiffyVersion warning. Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Tue Mar 2 13:06:16 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 13:06:16 0000 Subject: [squeak-dev] The Inbox: System-ct.1220.mcz Message-ID: Christoph Thiede uploaded a new version of System to project The Inbox: http://source.squeak.org/inbox/System-ct.1220.mcz ==================== Summary ==================== Name: System-ct.1220 Author: ct Time: 2 March 2021, 2:06:08.80617 pm UUID: cf9872fd-fa5d-4bb6-bc1c-8ced48a02a48 Ancestors: System-mt.1219 Adds Jaromir Matas (jar) to the authors list. A late welcome aboard! :-) =============== Diff against System-mt.1219 =============== Item was changed: ----- Method: SystemNavigation class>>privateAuthorsRaw (in category 'class initialization') ----- (excessive size, no diff calculated) Item was changed: + (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors.......'! - (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors......'! From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 13:13:10 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 13:13:10 +0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1371.mcz In-Reply-To: References: Message-ID: <31580866a49e48d0bcd4b62a17a1262f@student.hpi.uni-potsdam.de> Cool, nice utility - even though it does not support good readability of your code for sure :-) I have always used "thisContext return" for a similar result. :-D What about supporting a return argument here as well, like: self value: [ :ret | ^ ret ] ? This could increase the usefulness of #valueWithExit, but on the other hand, all clients would need to send #cull: or #value:. Any opinions? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Mittwoch, 17. Februar 2021 17:56:32 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-mt.1371.mcz Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1371.mcz ==================== Summary ==================== Name: Kernel-mt.1371 Author: mt Time: 17 February 2021, 5:56:29.152426 pm UUID: 1e5b05c3-feb7-e945-a253-3218ee358e74 Ancestors: Kernel-mt.1370 Extracts better examples for #valueWithExit from squeak-dev mailing list. =============== Diff against Kernel-mt.1370 =============== Item was changed: ----- Method: BlockClosure>>valueWithExit (in category 'evaluating') ----- valueWithExit + "Provides an exit block to the receiver. Use it to break out of the control flow with an early return. Examples below. + [:break | 1 to: 10 do: [:each | each > 5 ifTrue: [break value]]] valueWithExit. + 1 to: 10 do: [:each | [:continue | each > 5 ifTrue: [continue value]] valueWithExit]." - "Provides an exit block to the receiver. Use it to break out of the control flow with an early return. For example: - [:exit | 1 to: 10 do: [:each | each > 5 ifTrue: [exit value]]] valueWithExit" self value: [ ^nil ]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 13:17:09 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 13:17:09 +0000 Subject: [squeak-dev] The Trunk: Kernel-eem.1367.mcz In-Reply-To: References: Message-ID: <36e951e09a0b456fa929882903ff9f74@student.hpi.uni-potsdam.de> Hi Eliot, thanks for the fix! Sorry for raising the same question again, but wouldn't it still be safer to dispense with the #isArray call here? It allows the simulated code to break out of the simulation by overriding #isArray anywhere. I think I posted a proof of concept here: http://forum.world.st/The-Trunk-Kernel-eem-1366-mcz-tp5126558p5126713.html :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 2. Februar 2021 03:57:12 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-eem.1367.mcz Eliot Miranda uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-eem.1367.mcz ==================== Summary ==================== Name: Kernel-eem.1367 Author: eem Time: 1 February 2021, 6:57:09.713484 pm UUID: def9aaa1-eb71-4da5-8f86-85856d9b88ad Ancestors: Kernel-eem.1366 Fix mistake in the previous commit. Thanks Levente! =============== Diff against Kernel-eem.1366 =============== Item was changed: ----- Method: Context>>isPrimFailToken: (in category 'private') ----- + isPrimFailToken: contextOrPrimFailToken + "Answer if contextOrPrimFailToken, which will either be a Context object or + a primitive fail token (a tuple of the PrimitiveFailToken unique object and + a primitive failure code), is the latter. This should only be used with the + (possibly indirect) results of Context>>doPrimitive:method:receiver:args:" + ^contextOrPrimFailToken isArray + and: [contextOrPrimFailToken size = 2 + and: [(contextOrPrimFailToken at: 1) == PrimitiveFailToken]]! - isPrimFailToken: anObject - ^(self objectClass: anObject) isArray - and: [anObject size = 2 - and: [(anObject at: 1) == PrimitiveFailToken]]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 13:17:50 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 13:17:50 +0000 Subject: [squeak-dev] The Trunk: Tools-mt.1025.mcz In-Reply-To: References: , Message-ID: <1b9495e03d3e4fc68d45b1d71c205d85@student.hpi.uni-potsdam.de> Wow, that's a nice extension! Thank you Marcel! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Donnerstag, 18. Februar 2021 11:20:41 An: squeak-dev Betreff: Re: [squeak-dev] The Trunk: Tools-mt.1025.mcz [cid:d991405c-3612-459e-ae58-46f61fd467c1] Am 18.02.2021 11:20:04 schrieb commits at source.squeak.org : Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1025.mcz ==================== Summary ==================== Name: Tools-mt.1025 Author: mt Time: 18 February 2021, 11:19:50.596465 am UUID: 3a18ed90-267b-f545-86b6-a8edb2631a80 Ancestors: Tools-mt.1024 Add scoping and inverted lookup to dependency browser. I am using it for "DependencyBrowser openInvertedOn: #(EToys)" =============== Diff against Tools-mt.1024 =============== Item was changed: CodeHolder subclass: #DependencyBrowser + instanceVariableNames: 'packageList packageDeps packageDepsList classDeps classDepsList classList messageList packageListIndex packageDepsIndex classDepsIndex classListIndex messageListIndex autoSelectString windowTitle' - instanceVariableNames: 'packageList packageDeps packageDepsList classDeps classDepsList classList messageList packageListIndex packageDepsIndex classDepsIndex classListIndex messageListIndex autoSelectString' classVariableNames: '' poolDictionaries: '' category: 'Tools-Browser'! !DependencyBrowser commentStamp: 'fbs 5/6/2011 11:29' prior: 0! A simple dependency browser showing five panes: [1]: Packages: The list of available packages in the system. [2]: Package Dependencies: The dependent packages of the currently selected package. [3]: Class Dependencies: The classes causing the dependencies. [4]: Class List: The classes introducing the dependencies. [5]: Messages: The messages introducing the dependencies.! Item was added: + ----- Method: DependencyBrowser class>>openInvertedOn: (in category 'opening') ----- + openInvertedOn: requiredPackageNames + "DependencyBrowser openInvertedOn: #(Monticello)" + + | model | + model := self new. + ^ ToolBuilder open: ( + model + packageList: (model packageList select: [:packageName | + model computePackageDependencies: packageName. + model packageDeps includesAnyOf: requiredPackageNames]); + windowTitle: ('Dependency Browser (inverted on {1})' format: {requiredPackageNames}); + yourself) + ! Item was added: + ----- Method: DependencyBrowser class>>openOn: (in category 'opening') ----- + openOn: packageNames + "DependencyBrowser openOn: #(Morphic EToys)" + + ^ ToolBuilder open: (self new + packageList: packageNames; + windowTitle: 'Dependency Browser (on selected packages)'; + yourself)! Item was added: + ----- Method: DependencyBrowser>>packageList: (in category 'package list') ----- + packageList: somePackageNames + + packageList := somePackageNames. + self packageListIndex: 0.! Item was added: + ----- Method: DependencyBrowser>>windowTitle (in category 'accessing') ----- + windowTitle + + ^ windowTitle ifNil: ['Dependency Browser']! Item was added: + ----- Method: DependencyBrowser>>windowTitle: (in category 'accessing') ----- + windowTitle: aString + + windowTitle := aString. + self changed: #windowTitle.! -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 127537 bytes Desc: image.png URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 13:30:02 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 13:30:02 +0000 Subject: [squeak-dev] What about "self currentProject"? In-Reply-To: References: Message-ID: Hi Marcel, could you maybe share some more details about this particular design goal of Newspeak? :-) At the first glance, I do not really see the advantages of moving more and more "global getters" to Object. It: - inflates the Object protocol even more - might imply that there is some connection between the receiver and the project, or at least hide the global state (which one also could call "code perfuming" :-)) - and I don't see how it could help to replace the global object at all - you still need to wrap relevant calls with #becomeActiveDuring:, or speaking more in general about the proposed idiom, you would still need something like method wrappers unless you only want to override #currentThing for a single instance. So what possible advantages am I missing right now? :) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 2. März 2021 10:03:02 An: squeak-dev Betreff: [squeak-dev] What about "self currentProject"? Hi all! After typing "Project current" for the n-th time, I was wondering, whether "self currentProject" could be a nice little idiom for the Squeak environment. We had several thoughts on this matter: http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072 http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html 1. Object >> #currentProject would be a *System extension in Object to not be dependent on Morphic. 2. "Project current world" could be replaced with "self currentProject world" (generic) or "self currentWorld" (specific to Morphic). 3. "Project uiManager" could be replaced with "self currentProject uiManager". 4. "Project current addDeferredUIMessage:" could be replaced with "self currentProject addDeferredUIMessage:". So, we wouldn't have so many class references to "Project" in the code. It kind of reminds me about some of Newspeak's design goals. :-) What do you think? Best, Marcel -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 2 13:34:49 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 2 Mar 2021 14:34:49 +0100 Subject: [squeak-dev] What about "self currentProject"? In-Reply-To: References: Message-ID: Class references are global references. The piece "self currentProject" does not reveal where it is coming from. It is a good thing to not expose global state to user code -- even if it is global at the moment. :-) Best, Marcel Am 02.03.2021 14:30:11 schrieb Thiede, Christoph : Hi Marcel, could you maybe share some more details about this particular design goal of Newspeak? :-) At the first glance, I do not really see the advantages of moving more and more "global getters" to Object. It: - inflates the Object protocol even more - might imply that there is some connection between the receiver and the project, or at least hide the global state (which one also could call "code perfuming" :-)) - and I don't see how it could help to replace the global object at all - you still need to wrap relevant calls with #becomeActiveDuring:, or speaking more in general about the proposed idiom, you would still need something like method wrappers unless you only want to override #currentThing for a single instance. So what possible advantages am I missing right now? :) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 2. März 2021 10:03:02 An: squeak-dev Betreff: [squeak-dev] What about "self currentProject"?   Hi all! After typing "Project current" for the n-th time, I was wondering, whether "self currentProject" could be a nice little idiom for the Squeak environment.  We had several thoughts on this matter: http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072 [http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072] http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html [http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html] 1. Object >> #currentProject would be a *System extension in Object to not be dependent on Morphic. 2.  "Project current world" could be replaced with "self currentProject world" (generic) or "self currentWorld" (specific to Morphic). 3. "Project uiManager" could be replaced with "self currentProject uiManager". 4. "Project current addDeferredUIMessage:" could be replaced with "self currentProject addDeferredUIMessage:". So, we wouldn't have so many class references to "Project" in the code. It kind of reminds me about some of Newspeak's design goals. :-) What do you think? Best, Marcel -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 2 13:36:40 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 13:36:40 0000 Subject: [squeak-dev] The Inbox: Morphic-ct.1732.mcz Message-ID: Christoph Thiede uploaded a new version of Morphic to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1732.mcz ==================== Summary ==================== Name: Morphic-ct.1732 Author: ct Time: 2 March 2021, 2:36:32.90317 pm UUID: 3670c695-6c43-d744-b2d7-03ac4e6217e8 Ancestors: Morphic-mt.1731 Updates description of #sendMouseWheelToKeyboardFocus preference. Reason: Since Windows 10, the MouseWheelRouting setting is enabled by default. =============== Diff against Morphic-mt.1731 =============== Item was changed: ----- Method: HandMorph class>>sendMouseWheelToKeyboardFocus (in category 'preferences') ----- sendMouseWheelToKeyboardFocus ^ SendMouseWheelToKeyboardFocus ifNil: [true]! From m at jaromir.net Tue Mar 2 13:54:35 2021 From: m at jaromir.net (Jaromir Matas) Date: Tue, 2 Mar 2021 07:54:35 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1376.mcz In-Reply-To: <1614672418445-0.post@n4.nabble.com> References: <1614539317095-0.post@n4.nabble.com> <1614642085549-0.post@n4.nabble.com> <1614672418445-0.post@n4.nabble.com> Message-ID: <1614693275237-0.post@n4.nabble.com> For consideration: isSuspended "A process is suspended if it has been suspended with the suspend primitive. It is distinguishable from the active process and a terminated process by having a non-nil suspendedContext that is either not the bottom context or has not reached its endPC." ^myList isNil and: [suspendedContext notNil and: [self isTerminated not]] >>> new suggested comment: "A process is suspended if it has non-nil suspended context (i.e. is new or previously suspended with the suspend primitive), is not terminated and not waiting in a queue (Processor or Semaphore/Mutex/etc., i.e. is not runnable or blocked)." The current #isSuspended suffers from the same inconsistency, i.e. answers true even after sending terminate (in rare cases). The fix is either modify the current condition mirroring the changes in #isTerminated or rephrase it using #isTerminated. I'd prefer the latter but I can't foresee all consequences. Advice welcome :) regards, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Tue Mar 2 14:43:54 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 14:43:54 0000 Subject: [squeak-dev] The Inbox: System-ct.1221.mcz Message-ID: Christoph Thiede uploaded a new version of System to project The Inbox: http://source.squeak.org/inbox/System-ct.1221.mcz ==================== Summary ==================== Name: System-ct.1221 Author: ct Time: 2 March 2021, 3:43:49.27617 pm UUID: 9d574208-4d9d-9549-b398-2b34b8fce241 Ancestors: System-mt.1219 Refactors removal of selectors. Deprecates #confirmRemovalOf:on: because of its high coupling and magic number return values. Also improves multilingual support. Please only merge together with {Tools-ct.1028. Protocols-ct.78}, (HelpSystem-Core-ct.124 isInTrunk ifTrue: [{HelpSystem-Core-ct.135}] ifFalse: [].) :-) =============== Diff against System-mt.1219 =============== Item was added: + ----- Method: SystemNavigation>>confirmAndRemoveSelector:class: (in category 'ui') ----- + confirmAndRemoveSelector: selector class: aClass + + | method allCalls browse remove | + method := MethodReference class: aClass selector: selector environment: self environment. + allCalls := self allCallsOn: selector. + + remove := true. + browse := false. + (allCalls anySatisfy: [:ea | ea ~= method]) ifTrue: [ + | choice | + choice := UIManager default + chooseFromLabeledValues: (OrderedDictionary newFrom: { + 'Remove it' translated -> []. + 'Remove, then browse senders' translated -> [browse := true]. + 'Don''t remove, but show me those senders' translated -> [remove := false. browse := true]. + 'Forget it -- do nothing -- sorry I asked' translated -> [remove := false] }) + title: ('The message "{1}" has {2}.' translated format: { + selector. + allCalls size > 1 + ifFalse: ['1 sender' translated] + ifTrue: ['{1} senders' translated format: {allCalls size}] }). + choice ifNil: [choice := [remove := false]]. + choice value]. + + remove ifTrue: [ + aClass removeSelector: selector]. + browse ifTrue: [ + self headingAndAutoselectForLiteral: selector do: [ :label :autoSelect | + self + browseMessageList: allCalls + name: label + autoSelect: autoSelect]]. + + ^ remove! Item was changed: ----- Method: SystemNavigation>>confirmRemovalOf:on: (in category 'ui') ----- confirmRemovalOf: aSelector on: aClass "Determine if it is okay to remove the given selector. Answer 1 if it should be removed, 2 if it should be removed followed by a senders browse, and 3 if it should not be removed." | count answer caption allCalls | + self deprecated: 'ct: Use #confirmAndRemoveSelector:class: instead.'. + allCalls := self allCallsOn: aSelector. (count := allCalls size) = 0 ifTrue: [^ 1]. "no senders -- let the removal happen without warning" count = 1 ifTrue: [(allCalls first actualClass == aClass and: [allCalls first methodSymbol == aSelector]) ifTrue: [^ 1]]. "only sender is itself" caption := 'The message "{1}" has {2} sender{3}.' translated format: {aSelector. count. count > 1 ifTrue: ['s'] ifFalse: ['']}. answer := UIManager default chooseFrom: #('Remove it' 'Remove, then browse senders' 'Don''t remove, but show me those senders' 'Forget it -- do nothing -- sorry I asked') title: caption. answer = 3 ifTrue: [self browseMessageList: allCalls name: 'Senders of ' , aSelector autoSelect: aSelector keywords first]. answer = 0 ifTrue: [answer := 3]. "If user didn't answer, treat it as cancel" ^ answer min: 3! From commits at source.squeak.org Tue Mar 2 14:44:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 14:44:33 0000 Subject: [squeak-dev] The Inbox: Tools-ct.1028.mcz Message-ID: Christoph Thiede uploaded a new version of Tools to project The Inbox: http://source.squeak.org/inbox/Tools-ct.1028.mcz ==================== Summary ==================== Name: Tools-ct.1028 Author: ct Time: 2 March 2021, 3:44:29.75717 pm UUID: 9b55450f-acf1-274e-b4fd-a502f8a89d86 Ancestors: Tools-mt.1027 Refactors removal of selectors. Complements System-ct.1221. Includes deduplication, better reusage of the removal confirmation dialogs, and fixes the "remove and/or browse" options for the FileContentsBrowser. =============== Diff against Tools-mt.1027 =============== Item was changed: ----- Method: Browser>>removeMessage (in category 'message functions') ----- removeMessage + + self hasMessageSelected ifFalse: [^ false]. + + super removeMessage ifFalse: [^ false]. - "If a message is selected, create a Confirmer so the user can verify that - the currently selected message should be removed from the system. If - so, - remove it. If the Preference 'confirmMethodRemoves' is set to false, the - confirmer is bypassed." - | messageName confirmation | - self hasMessageSelected not - ifTrue: [^ self]. - self okToChange - ifFalse: [^ self]. - messageName := self selectedMessageName. - confirmation := self systemNavigation confirmRemovalOf: messageName on: self selectedClassOrMetaClass. - confirmation = 3 - ifTrue: [^ self]. - self selectedClassOrMetaClass removeSelector: messageName. self selectMessageNamed: nil. self changed: #messageList. self setClassOrganizer. + + ^ true! - "In case organization not cached" - confirmation = 2 - ifTrue: [self systemNavigation browseAllCallsOn: messageName]! Item was changed: ----- Method: ChangeSorter>>removeMessage (in category 'message list') ----- removeMessage + + ^ super removeMessage + ifTrue: [self update]; + yourself! - "Remove the selected msg from the system. Real work done by the - parent, a ChangeSorter" - | confirmation sel | - self okToChange - ifFalse: [^ self]. - currentSelector - ifNotNil: [confirmation := self systemNavigation confirmRemovalOf: (sel := self selectedMessageName) on: self selectedClassOrMetaClass. - confirmation = 3 - ifTrue: [^ self]. - self selectedClassOrMetaClass removeSelector: sel. - self update. - confirmation = 2 - ifTrue: [self systemNavigation browseAllCallsOn: sel]]! Item was added: + ----- Method: CodeHolder>>removeMessage (in category 'commands') ----- + removeMessage + "If a message is selected, create a Confirmer so the user can verify that the currently selected message should be removed from the system. If so, remove it. Answer a boolean indicating whether the removal was succesful." + self okToChange ifFalse: [^ false]. + + ^ self systemNavigation + confirmAndRemoveSelector: self selectedMessageName + class: self selectedClassOrMetaClass! Item was changed: ----- Method: Debugger>>removeMessage (in category 'context stack menu') ----- removeMessage + | oldContext method cleanIndex | - | oldContext method cleanIndex confirmation | self okToChange ifFalse: [^ false]. contextStackIndex isZero ifTrue: [^ false]. oldContext := self selectedContext. method := oldContext method. cleanIndex := self findCleanHomeBelow: method. contextStack at: cleanIndex ifAbsent: [ self inform: 'Sender of method not found on stack, can''t remove message'. ^ false]. (self confirm: 'I will have to revert to the sender of this message. Is that OK?') ifFalse: [^ false]. + super removeMessage ifFalse: [^ false]. - confirmation := self systemNavigation - confirmRemovalOf: method selector - on: method methodClass. - confirmation = 3 ifTrue: [^ self]. - self selectedClassOrMetaClass removeSelector: method selector. - self contextStackIndex: cleanIndex oldContextWas: oldContext; tryRestartFrom: self selectedContext. + + ^ true! - confirmation = 2 - ifTrue: [self systemNavigation browseAllCallsOn: method selector].! Item was changed: ----- Method: FileContentsBrowser>>removeMessage (in category 'removing') ----- removeMessage + + self hasMessageSelected ifFalse: [^ false]. + + super removeMessage ifFalse: [^ false]. - | messageName | - self hasMessageSelected - ifFalse: [^ self]. - self okToChange - ifFalse: [^ self]. - messageName := self selectedMessageName. - (self selectedClass confirmRemovalOf: messageName) - ifFalse: [^ false]. - self selectedClassOrMetaClass removeMethod: self selectedMessageName. self selectMessageNamed: nil. self setClassOrganizer. "In case organization not cached" + self changed: #messageList.! - self changed: #messageList! Item was changed: ----- Method: MessageSet>>removeMessage (in category 'message functions') ----- removeMessage + + self hasMessageSelected ifFalse: [^ false]. + + super removeMessage ifFalse: [^ false]. - "Remove the selected message from the system. 1/15/96 sw" - | messageName confirmation | - self hasMessageSelected - ifFalse: [^ self]. - self okToChange - ifFalse: [^ self]. - messageName := self selectedMessageName. - confirmation := self systemNavigation confirmRemovalOf: messageName on: self selectedClassOrMetaClass. - confirmation = 3 - ifTrue: [^ self]. - self selectedClassOrMetaClass removeSelector: messageName. self deleteFromMessageList: self selection. self reformulateList. + + ^ true! - confirmation = 2 - ifTrue: [self systemNavigation browseAllCallsOn: messageName]! Item was changed: ----- Method: MessageTrace>>removeMessage (in category 'actions') ----- removeMessage "Remove the selected messages from the system." self selectedMessages size = 0 ifTrue: [ ^self ]. self selectedMessages size = 1 ifTrue: [ ^super removeMessage ]. + (self confirm: ('Are you certain you want to remove all the {1} selected methods from the image?' translated format: {self selectedMessages size})) ifFalse: [ ^self ]. - (self confirm: 'Are you certain you want to remove all of the selected methods from the image?') ifFalse: [ ^self ]. self selectedMessages do: [ :each | each actualClass removeSelector: each methodSymbol. self deleteFromMessageList: each ]! From commits at source.squeak.org Tue Mar 2 14:45:11 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 14:45:11 0000 Subject: [squeak-dev] The Inbox: HelpSystem-Core-ct.134.mcz Message-ID: Christoph Thiede uploaded a new version of HelpSystem-Core to project The Inbox: http://source.squeak.org/inbox/HelpSystem-Core-ct.134.mcz ==================== Summary ==================== Name: HelpSystem-Core-ct.134 Author: ct Time: 2 March 2021, 3:45:09.69417 pm UUID: 427affe2-8ef9-464d-9f35-3b42e41eecc9 Ancestors: HelpSystem-Core-ct.124 Refactors removal of selectors. Complements System-ct.1221. Depends indeed on HelpSystem-Core-ct.124 (inbox). =============== Diff against HelpSystem-Core-ct.124 =============== Item was changed: ----- Method: ClassBasedHelpTopic>>removeSubtopic: (in category 'editing') ----- removeSubtopic: aTopic + | needsToStorePages oldPages | + aTopic isClassBasedHelpTopic ifTrue: [ + | result | + result := aTopic removeTopicClass. + result ifTrue: [self refresh]. + ^ result]. - | needsToStorePages confirmation oldPages | - aTopic isClassBasedHelpTopic - ifTrue: [ - | result | - result := aTopic removeTopicClass. - result ifTrue: [self refresh]. - ^ result]. aTopic key ifNil: [ self inform: 'Could not find topic' translated. ^ false]. + (self confirm: ('Are you sure you want to REMOVE the topic "{1}" from "{2}"?' translated format: {aTopic title. self title})) ifFalse: [^ false]. + needsToStorePages := self needsToStorePages. needsToStorePages ifTrue: [ (self okToWriteSelector: #pages) ifFalse: [^ false]. oldPages := self helpClass pages]. + + (self systemNavigation + confirmAndRemoveSelector: aTopic key + class: self helpClass theMetaClass) + ifFalse: [^ false]. + - confirmation := self systemNavigation - confirmRemovalOf: aTopic key - on: self helpClass theMetaClass. - confirmation = 3 ifTrue: [^ false]. - self helpClass theMetaClass removeSelector: aTopic key. needsToStorePages ifTrue: [ self storePages: (oldPages copyWithout: aTopic key)]. - self refresh. - confirmation = 2 ifTrue: [ - self systemNavigation browseAllCallsOn: aTopic key]. ^ true! From commits at source.squeak.org Tue Mar 2 14:45:38 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 14:45:38 0000 Subject: [squeak-dev] The Inbox: Protocols-ct.78.mcz Message-ID: Christoph Thiede uploaded a new version of Protocols to project The Inbox: http://source.squeak.org/inbox/Protocols-ct.78.mcz ==================== Summary ==================== Name: Protocols-ct.78 Author: ct Time: 2 March 2021, 3:45:36.46717 pm UUID: 0213a785-c806-e344-83fb-4876ec5be7ee Ancestors: Protocols-mt.77 Refactors removal of selectors. Complements System-ct.1221. =============== Diff against Protocols-mt.77 =============== Item was changed: ----- Method: Lexicon>>removeMessage (in category 'menu commands') ----- removeMessage - "Remove the selected message from the system." + super removeMessage ifFalse: [^ false]. + - messageListIndex = 0 ifTrue: [^ self]. - self okToChange ifFalse: [^ self]. - - super removeMessage. "my #reformulateList method, called from the super #removeMethod method, will however try to preserve the selection, so we take pains to clobber it by the below..." messageListIndex := 0. self changed: #messageList. self changed: #messageListIndex. contents := nil. self contentsChanged! From m at jaromir.net Tue Mar 2 14:46:18 2021 From: m at jaromir.net (Jaromir Matas) Date: Tue, 2 Mar 2021 08:46:18 -0600 (CST) Subject: [squeak-dev] The Trunk: Kernel-mt.1371.mcz In-Reply-To: <31580866a49e48d0bcd4b62a17a1262f@student.hpi.uni-potsdam.de> References: <31580866a49e48d0bcd4b62a17a1262f@student.hpi.uni-potsdam.de> Message-ID: <1614696378126-0.post@n4.nabble.com> Really nice! I'd just add a return to behave like a normal #value in case the non-local return doesn't happen: ^self value: [ :ret | ^ ret ] Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 2 14:47:05 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 2 Mar 2021 08:47:05 -0600 (CST) Subject: [squeak-dev] The Inbox: System-ct.1221.mcz In-Reply-To: References: Message-ID: <1614696425832-0.post@n4.nabble.com> > Please only merge together with {Tools-ct.1028. Protocols-ct.78}, (HelpSystem-Core-ct.124 isInTrunk ifTrue: [{HelpSystem-Core-ct.135}] ifFalse: [].) :-) Instead of HelpSystem-Core-ct.135, I was referring to HelpSystem-Core-ct.134. Sorry for the confusion! Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Tue Mar 2 14:54:11 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 14:54:11 0000 Subject: [squeak-dev] The Inbox: Protocols-ct.79.mcz Message-ID: Christoph Thiede uploaded a new version of Protocols to project The Inbox: http://source.squeak.org/inbox/Protocols-ct.79.mcz ==================== Summary ==================== Name: Protocols-ct.79 Author: ct Time: 2 March 2021, 3:54:08.19017 pm UUID: e33c4359-8d90-8e4f-9c3d-b2ed45ee3ac9 Ancestors: Protocols-mt.77 In the protocol lexicon, fall back to the "all" category if no certain protocol is selected. =============== Diff against Protocols-mt.77 =============== Item was changed: ----- Method: Lexicon>>categoryListIndex: (in category 'category list') ----- categoryListIndex: anIndex "Set the category list index as indicated" | categoryName aList found existingSelector | existingSelector := self selectedMessageName. categoryListIndex := anIndex. + categoryName := anIndex > 0 - anIndex > 0 ifTrue: + [categoryList at: anIndex] - [categoryName := categoryList at: anIndex] ifFalse: + [categoryList last "self class allCategoryName"]. - [contents := nil]. self changed: #categoryListIndex. found := false. #( (viewedCategoryName selectorsVisited) (queryCategoryName selectorsRetrieved)) do: [:pair | categoryName = (self class perform: pair first) ifTrue: [aList := self perform: pair second. found := true]]. found ifFalse: [aList := currentVocabulary allMethodsInCategory: categoryName forInstance: self targetObject ofClass: targetClass]. categoryName = self class queryCategoryName ifFalse: [autoSelectString := nil]. self initListFrom: aList highlighting: targetClass. messageListIndex := 0. self changed: #messageList. contents := nil. self contentsChanged. self selectWithinCurrentCategoryIfPossible: existingSelector. self adjustWindowTitle! From eliot.miranda at gmail.com Tue Mar 2 15:27:16 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Tue, 2 Mar 2021 07:27:16 -0800 Subject: [squeak-dev] The Trunk: Kernel-eem.1367.mcz In-Reply-To: <36e951e09a0b456fa929882903ff9f74@student.hpi.uni-potsdam.de> References: <36e951e09a0b456fa929882903ff9f74@student.hpi.uni-potsdam.de> Message-ID: Hi Christoph, > On Mar 2, 2021, at 5:17 AM, Thiede, Christoph wrote: > >  > Hi Eliot, > > > > thanks for the fix! Sorry for raising the same question again, but wouldn't it still be safer to dispense with the #isArray call here? It allows the simulated code to break out of the simulation by overriding #isArray anywhere. > As I understand it no. The clue is in the variable name. contextOrPrimFailToken can only ever be a Context or an Array, so the send of isArray serves only to quickly differentiate between a Context and an Array. The message doesn’t get sent to any other kinds of object at that point so the concern that other classes may define isArray does not apply here. > I think I posted a proof of concept here: http://forum.world.st/The-Trunk-Kernel-eem-1366-mcz-tp5126558p5126713.html :-) > > > Best, > Christoph > Von: Squeak-dev im Auftrag von commits at source.squeak.org > Gesendet: Dienstag, 2. Februar 2021 03:57:12 > An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org > Betreff: [squeak-dev] The Trunk: Kernel-eem.1367.mcz > > Eliot Miranda uploaded a new version of Kernel to project The Trunk: > http://source.squeak.org/trunk/Kernel-eem.1367.mcz > > ==================== Summary ==================== > > Name: Kernel-eem.1367 > Author: eem > Time: 1 February 2021, 6:57:09.713484 pm > UUID: def9aaa1-eb71-4da5-8f86-85856d9b88ad > Ancestors: Kernel-eem.1366 > > Fix mistake in the previous commit. Thanks Levente! > > =============== Diff against Kernel-eem.1366 =============== > > Item was changed: > ----- Method: Context>>isPrimFailToken: (in category 'private') ----- > + isPrimFailToken: contextOrPrimFailToken > + "Answer if contextOrPrimFailToken, which will either be a Context object or > + a primitive fail token (a tuple of the PrimitiveFailToken unique object and > + a primitive failure code), is the latter. This should only be used with the > + (possibly indirect) results of Context>>doPrimitive:method:receiver:args:" > + ^contextOrPrimFailToken isArray > + and: [contextOrPrimFailToken size = 2 > + and: [(contextOrPrimFailToken at: 1) == PrimitiveFailToken]]! > - isPrimFailToken: anObject > - ^(self objectClass: anObject) isArray > - and: [anObject size = 2 > - and: [(anObject at: 1) == PrimitiveFailToken]]! > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 2 16:03:22 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 16:03:22 0000 Subject: [squeak-dev] The Inbox: Collections-ct.925.mcz Message-ID: Christoph Thiede uploaded a new version of Collections to project The Inbox: http://source.squeak.org/inbox/Collections-ct.925.mcz ==================== Summary ==================== Name: Collections-ct.925 Author: ct Time: 2 March 2021, 5:03:16.49317 pm UUID: 5f3ec2e0-cb35-a74d-9a02-1ef8f9f78aeb Ancestors: Collections-jar.924 Refines String>>#asPluralBasedOn: to avoid ugly spellings such as 'classs'. This approach does not scale very far, of course, but it's better than nothing. Maybe we also want to move this into System-Localization at some other day and build language-specific plurals. :-) =============== Diff against Collections-jar.924 =============== Item was changed: ----- Method: String>>asPluralBasedOn: (in category 'converting') ----- asPluralBasedOn: aNumberOrCollection "Append an 's' to this string based on whether aNumberOrCollection is 1 or of size 1." + aNumberOrCollection = 1 + ifTrue: [^ self]. + (aNumberOrCollection isCollection and: [aNumberOrCollection size = 1]) + ifTrue: [^ self]. + + ^ (self endsWith: 's') + ifTrue: [self , 'es'] + ifFalse: [self , 's'] - ^ (aNumberOrCollection = 1 or: - [aNumberOrCollection isCollection and: [aNumberOrCollection size = 1]]) - ifTrue: [self] - ifFalse: [self, 's'] ! From commits at source.squeak.org Tue Mar 2 16:06:05 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 16:06:05 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1732.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1732.mcz ==================== Summary ==================== Name: Morphic-mt.1732 Author: mt Time: 2 March 2021, 5:06:00.167687 pm UUID: cb835785-768b-fd48-8eef-af27742a70dc Ancestors: Morphic-mt.1731 Encapsulates most of the logic for halo invocation (and transfer) from Morph and PasteUpMorph into a new MorphicHaloDispatcher. Hopefully no new bugs introduced. Yet, there is still this issue with protruding submorphs due to the logic in #dispatchHalo:createFor: ... :-) PasteUpMorph #tryInvokeHalo: --> #dispatchHalo:createFor: Morph #transferHalo:from: --> #dispatchHalo:transferFrom: It always starts in #dispatchHalo:with: --- either called from the world's event filter or the current halo's mouse-down handling code. =============== Diff against Morphic-mt.1731 =============== Item was removed: - ----- Method: Morph>>addHalo:from: (in category 'halos and balloon help') ----- - addHalo: evt from: formerHaloOwner - "Transfer a halo from the former halo owner to the receiver" - ^self addHalo: evt! Item was added: + ----- Method: Morph>>defaultHaloDispatcher (in category 'halos and balloon help') ----- + defaultHaloDispatcher + + ^ MorphicHaloDispatcher new! Item was removed: - ----- Method: Morph>>invokeHaloOrMove: (in category 'meta-actions') ----- - invokeHaloOrMove: anEvent - "Special gestures (cmd-mouse on the Macintosh; Alt-mouse on Windows and Unix) allow a mouse-sensitive morph to be moved or bring up a halo for the morph." - | h tfm doNotDrag | - h := anEvent hand halo. - "Prevent wrap around halo transfers originating from throwing the event back in" - doNotDrag := false. - h ifNotNil:[ - (h innerTarget == self) ifTrue:[doNotDrag := true]. - (h innerTarget hasOwner: self) ifTrue:[doNotDrag := true]. - (self hasOwner: h target) ifTrue:[doNotDrag := true]]. - - tfm := (self transformedFrom: nil) inverseTransformation. - - "cmd-drag on flexed morphs works better this way" - h := self addHalo: (anEvent transformedBy: tfm). - h ifNil: [^ self]. - doNotDrag ifTrue:[^self]. - "Initiate drag transition if requested" - anEvent hand - waitForClicksOrDrag: h - event: (anEvent transformedBy: tfm) - selectors: { nil. nil. nil. #startDragTarget:. } - threshold: HandMorph dragThreshold. - "Pass focus explicitly here" - anEvent hand newMouseFocus: h. - "Reset temporary cursors to make available halo interaction visible." - anEvent hand showTemporaryCursor: nil.! Item was added: + ----- Method: Morph>>transferHalo: (in category 'halos and balloon help') ----- + transferHalo: event + + ^ self transferHalo: event using: self defaultHaloDispatcher! Item was removed: - ----- Method: Morph>>transferHalo:from: (in category 'halos and balloon help') ----- - transferHalo: event from: formerHaloOwner - "Progressively transfer the halo to the next likely recipient" - | localEvt w target | - - self flag: #workAround. "For halo's distinction between 'target' and 'innerTarget' we need to bypass any renderers." - (formerHaloOwner == self and:[self isRenderer and:[self wantsHaloFromClick not]]) ifTrue:[ - event shiftPressed ifTrue:[ - target := owner. - localEvt := event transformedBy: (self transformedFrom: owner). - ] ifFalse:[ - target := self renderedMorph. - localEvt := event transformedBy: (target transformedFrom: self). - ]. - ^target transferHalo: localEvt from: target]. - - " formerHaloOwner == self ifTrue:[^ self removeHalo]." - - "Never transfer halo to top-most world" - (self isWorldMorph and:[owner isNil]) ifFalse:[ - (self wantsHaloFromClick and:[formerHaloOwner ~~ self]) - ifTrue:[^self addHalo: event from: formerHaloOwner]]. - - event shiftPressed ifTrue:[ - "Pass it outwards" - owner ifNotNil:[^owner transferHalo: event from: formerHaloOwner]. - "We're at the top level; throw the event back in to find recipient" - formerHaloOwner removeHalo. - ^self processEvent: event copy resetHandlerFields. - ]. - self submorphsDo:[:m| - localEvt := event transformedBy: (m transformedFrom: self). - (m fullContainsPoint: localEvt position) - ifTrue:[^m transferHalo: event from: formerHaloOwner]. - ]. - "We're at the bottom most level; throw the event back up to the root to find recipient" - formerHaloOwner removeHalo. - - Preferences maintainHalos ifFalse:[ - (w := self world) ifNil: [ ^self ]. - localEvt := event transformedBy: (self transformedFrom: w) inverseTransformation. - ^w processEvent: localEvt resetHandlerFields. - ]. - ! Item was added: + ----- Method: Morph>>transferHalo:using: (in category 'halos and balloon help') ----- + transferHalo: event using: dispatcher + + ^ dispatcher dispatchHalo: event with: self! Item was added: + Object subclass: #MorphicHaloDispatcher + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Morphic-Events'! Item was added: + ----- Method: MorphicHaloDispatcher>>dispatchHalo:createFor: (in category 'dispatching') ----- + dispatchHalo: anEvent createFor: aMorph + "Invoke halos around the top-most world container at aUserInputEvent's #position. If it was already halo'd, zero-in on its next inward component morph at that position. Holding Shift during the click reverses this traversal order." + + | stack innermost haloTarget | + "the stack is the top-most morph to bottom-most." + stack := (aMorph morphsAt: anEvent position unlocked: true) select: + [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: anEvent ] ]. + innermost := anEvent hand halo + ifNil: [ stack first ] + ifNotNil: + [ : existingHalo | + (stack := stack copyWithout: existingHalo) "No halos on halos" + detect: [ : each | each owner == aMorph ] + ifFound: + [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?" + (existingHalo target withAllOwners includes: worldContainer) + ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now." ^ false ] + ifFalse: + [ "different hierarchy, remove + add." + anEvent hand removeHalo. + anEvent shiftPressed + ifTrue: [ stack first ] + ifFalse: [ worldContainer ] ] ] + ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now." ^ false ] ]. + + "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))." + haloTarget := (innermost == aMorph or: [anEvent shiftPressed]) + ifTrue: [ innermost ] + ifFalse: + [ "Find the outermost owner that wants it." + innermost withAllOwners reversed allButFirst + detect: [ : each | each wantsHaloFromClick ] + ifNone: [ "haloTarget has its own mouseDown handler, don't halo." ^ false ] ]. + "Now that we have the haloTarget, show the halo." + self invokeHaloOrMove: anEvent on: haloTarget. + ^ true! Item was added: + ----- Method: MorphicHaloDispatcher>>dispatchHalo:transferFrom: (in category 'dispatching') ----- + dispatchHalo: event transferFrom: morph + "Progressively transfer the halo to the next likely recipient" + + ^ event shiftPressed + ifTrue: [self dispatchHalo: event transferOutwardsFrom: morph] + ifFalse: [self dispatchHalo: event transferInwardsFrom: morph]! Item was added: + ----- Method: MorphicHaloDispatcher>>dispatchHalo:transferInwardsFrom: (in category 'dispatching') ----- + dispatchHalo: event transferInwardsFrom: currentTarget + + | localEvent world | + currentTarget submorphsDo: [:nextTarget | + localEvent := event transformedBy: (nextTarget transformedFrom: currentTarget). + (nextTarget fullContainsPoint: localEvent position) ifTrue: [ + ^ nextTarget wantsHaloFromClick + ifTrue: [self invokeHalo: localEvent on: nextTarget] + ifFalse: [self dispatchHalo: localEvent transferInwardsFrom: nextTarget]]]. + + "We're at the bottom most level; throw the event back up to the root to find recipient" + event hand removeHalo. + Preferences maintainHalos ifFalse: [ + (world := currentTarget world) ifNil: [ ^ false ]. + localEvent := event transformedBy: (currentTarget transformedFrom: world) inverseTransformation. + world processEvent: localEvent resetHandlerFields]. + + ^ false! Item was added: + ----- Method: MorphicHaloDispatcher>>dispatchHalo:transferOutwardsFrom: (in category 'dispatching') ----- + dispatchHalo: event transferOutwardsFrom: currentTarget + + | localEvent | + currentTarget owner ifNotNil: [:nextTarget | + localEvent := event transformedBy: (currentTarget transformedFrom: nextTarget). + "Never transfer halo to top-most world" + ^ (nextTarget isWorldMorph not and: [nextTarget wantsHaloFromClick]) + ifTrue: [self invokeHalo: localEvent on: nextTarget] + ifFalse: [self dispatchHalo: localEvent transferOutwardsFrom: nextTarget]]. + + "We're at the top level; throw the event back in to find recipient" + event hand removeHalo. + currentTarget isWorldMorph + ifTrue: [currentTarget processEvent: event copy resetHandlerFields]. + + ^ false! Item was added: + ----- Method: MorphicHaloDispatcher>>dispatchHalo:with: (in category 'dispatching') ----- + dispatchHalo: anEvent with: aMorph + + | halo successful | + halo := anEvent hand halo. + successful := (halo isNil or: [halo target ~~ aMorph]) + ifTrue: [self dispatchHalo: anEvent createFor: aMorph] + ifFalse: [self dispatchHalo: anEvent transferFrom: aMorph]. + successful ifTrue: [ + self assert: [halo ~~ anEvent hand halo]. + anEvent hand halo setProperty: #lastHaloDispatcher toValue: self]. + ^ successful! Item was added: + ----- Method: MorphicHaloDispatcher>>invokeHalo:on: (in category 'invoking') ----- + invokeHalo: anEvent on: aMorph + + aMorph addHalo: anEvent. + ^ true! Item was added: + ----- Method: MorphicHaloDispatcher>>invokeHaloOrMove:on: (in category 'invoking') ----- + invokeHaloOrMove: anEvent on: aMorph + "Special gestures (cmd-mouse on the Macintosh; Alt-mouse on Windows and Unix) allow a mouse-sensitive morph to be moved or bring up a halo for the morph." + | h tfm doNotDrag | + anEvent hand newMouseFocus: aMorph event: anEvent. + h := anEvent hand halo. + "Prevent wrap around halo transfers originating from throwing the event back in" + doNotDrag := false. + h ifNotNil:[ + (h innerTarget == aMorph) ifTrue:[doNotDrag := true]. + (h innerTarget hasOwner: aMorph) ifTrue:[doNotDrag := true]. + (aMorph hasOwner: h target) ifTrue:[doNotDrag := true]]. + + tfm := (aMorph transformedFrom: nil) inverseTransformation. + + "cmd-drag on flexed morphs works better this way" + h := aMorph addHalo: (anEvent transformedBy: tfm). + h setProperty: #lastHaloDispatcher toValue: self. + doNotDrag ifTrue:[^ true]. + "Initiate drag transition if requested" + anEvent hand + waitForClicksOrDrag: h + event: (anEvent transformedBy: tfm) + selectors: { nil. nil. nil. #startDragTarget:. } + threshold: HandMorph dragThreshold. + "Pass focus explicitly here" + anEvent hand newMouseFocus: h. + "Reset temporary cursors to make available halo interaction visible." + anEvent hand showTemporaryCursor: nil. + ^ true! Item was changed: ----- Method: PasteUpMorph>>tryInvokeHalo: (in category 'events-processing') ----- tryInvokeHalo: aUserInputEvent + - "Invoke halos around the top-most world container at aUserInputEvent's #position. If it was already halo'd, zero-in on its next inward component morph at that position. Holding Shift during the click reverses this traversal order." - | stack innermost haloTarget | Preferences noviceMode ifTrue: [ ^ self ]. Morph haloForAll ifFalse: [ ^ self ]. + + (self transferHalo: aUserInputEvent) + ifTrue: "The event was handled, don't let it cause any further side-effects." + [ aUserInputEvent ignore ].! - "the stack is the top-most morph to bottom-most." - stack := (self morphsAt: aUserInputEvent position unlocked: true) select: - [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: aUserInputEvent ] ]. - innermost := aUserInputEvent hand halo - ifNil: [ stack first ] - ifNotNil: - [ : existingHalo | (stack copyWithout: existingHalo) "No halos on halos" - detect: [ : each | each owner == self ] - ifFound: - [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?" - (existingHalo target withAllOwners includes: worldContainer) - ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now." ^self ] - ifFalse: - [ "different hierarchy, remove + add." - aUserInputEvent hand removeHalo. - aUserInputEvent shiftPressed - ifTrue: [ stack second "first is still the just removed halo" ] - ifFalse: [ worldContainer ] ] ] - ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now." ^self ] ]. - "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))." - haloTarget := (innermost == self or: [aUserInputEvent shiftPressed]) - ifTrue: [ innermost ] - ifFalse: - [ "Find the outermost owner that wants it." - innermost withAllOwners reversed allButFirst - detect: [ : each | each wantsHaloFromClick ] - ifNone: [ "haloTarget has its own mouseDown handler, don't halo." ^ self ] ]. - "Now that we have the haloTarget, show the halo." - aUserInputEvent hand - newMouseFocus: haloTarget - event: aUserInputEvent. - haloTarget invokeHaloOrMove: aUserInputEvent. - "aUserInputEvent has been consumed, don't let it cause any further side-effects." - aUserInputEvent ignore! Item was changed: ----- Method: SimpleHaloMorph>>transferHalo: (in category 'pop up') ----- transferHalo: event "Transfer the halo to the next likely recipient" + ^ self + transferHalo: event + using: (self + valueOfProperty: #lastHaloDispatcher + ifAbsent: [self target defaultHaloDispatcher])! - self target - transferHalo: (event transformedBy: (self target transformedFrom: self)) - from: self target.! Item was removed: - ----- Method: SimpleHaloMorph>>transferHalo:from: (in category 'halos and balloon help') ----- - transferHalo: event from: formerHaloOwner - "If my world tries to open on me, pass it on to the next sibling after me." - - formerHaloOwner == self world ifTrue: [ - self world submorphsDo: [:m | - (m ~~ self and: [m fullContainsPoint: event position]) ifTrue: [ - m comeToFront. - ^ m transferHalo: event from: formerHaloOwner]]].! Item was added: + ----- Method: SimpleHaloMorph>>transferHalo:using: (in category 'pop up') ----- + transferHalo: event using: dispatcher + "Transfer the halo to the next likely recipient. Call the target again so that it may change the dispatcher." + + ^ self target + transferHalo: (event transformedBy: (self target transformedFrom: self)) + using: dispatcher! Item was added: + ----- Method: SimpleHaloMorph>>wantsHaloFromClick (in category 'halos and balloon help') ----- + wantsHaloFromClick + + ^ false! From commits at source.squeak.org Tue Mar 2 16:08:43 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 16:08:43 0000 Subject: [squeak-dev] The Trunk: EToys-mt.430.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.430.mcz ==================== Summary ==================== Name: EToys-mt.430 Author: mt Time: 2 March 2021, 5:08:34.225687 pm UUID: 001ccf96-161a-6848-a231-743877f0d41d Ancestors: EToys-mt.429 Complements Morphic-mt.1732. I think that the call in #mouseDown: is enough to stop recording. Yet, we might want to inform a morph when a halo was (or is about to be) openend on it. There is none yet. =============== Diff against EToys-mt.429 =============== Item was removed: - ----- Method: EventRecordingSpace>>invokeHaloOrMove: (in category 'events-processing') ----- - invokeHaloOrMove: anEvent - - (eventRecorder userStopReplayMaybe: anEvent) ifTrue: [^ self stopPlayback]. - super invokeHaloOrMove: anEvent. - ! From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 16:21:11 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 16:21:11 +0000 Subject: [squeak-dev] The Trunk: Kernel-eem.1367.mcz In-Reply-To: References: <36e951e09a0b456fa929882903ff9f74@student.hpi.uni-potsdam.de>, Message-ID: Hi Eliot, then I think there is an issue with the argument name. In #callPrimitive:, for example, it is named more specifically, maybePrimFailToken. In #doPrimitive:method:receiver:args:, we may feed it with the result of #tryPrimitive:withArgs: which can be anything, not only a context or fail token. Here is a second example: Object subclass: #ContextHack instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'CT-Experiments'. ContextHack class compile: 'isArray self error: #hacked'. ContextHack new class "through" Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Eliot Miranda Gesendet: Dienstag, 2. März 2021 16:27 Uhr An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] The Trunk: Kernel-eem.1367.mcz Hi Christoph, On Mar 2, 2021, at 5:17 AM, Thiede, Christoph wrote:  Hi Eliot, thanks for the fix! Sorry for raising the same question again, but wouldn't it still be safer to dispense with the #isArray call here? It allows the simulated code to break out of the simulation by overriding #isArray anywhere. As I understand it no. The clue is in the variable name. contextOrPrimFailToken can only ever be a Context or an Array, so the send of isArray serves only to quickly differentiate between a Context and an Array. The message doesn’t get sent to any other kinds of object at that point so the concern that other classes may define isArray does not apply here. I think I posted a proof of concept here: http://forum.world.st/The-Trunk-Kernel-eem-1366-mcz-tp5126558p5126713.html :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 2. Februar 2021 03:57:12 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-eem.1367.mcz Eliot Miranda uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-eem.1367.mcz ==================== Summary ==================== Name: Kernel-eem.1367 Author: eem Time: 1 February 2021, 6:57:09.713484 pm UUID: def9aaa1-eb71-4da5-8f86-85856d9b88ad Ancestors: Kernel-eem.1366 Fix mistake in the previous commit. Thanks Levente! =============== Diff against Kernel-eem.1366 =============== Item was changed: ----- Method: Context>>isPrimFailToken: (in category 'private') ----- + isPrimFailToken: contextOrPrimFailToken + "Answer if contextOrPrimFailToken, which will either be a Context object or + a primitive fail token (a tuple of the PrimitiveFailToken unique object and + a primitive failure code), is the latter. This should only be used with the + (possibly indirect) results of Context>>doPrimitive:method:receiver:args:" + ^contextOrPrimFailToken isArray + and: [contextOrPrimFailToken size = 2 + and: [(contextOrPrimFailToken at: 1) == PrimitiveFailToken]]! - isPrimFailToken: anObject - ^(self objectClass: anObject) isArray - and: [anObject size = 2 - and: [(anObject at: 1) == PrimitiveFailToken]]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From eliot.miranda at gmail.com Tue Mar 2 17:05:37 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Tue, 2 Mar 2021 09:05:37 -0800 Subject: [squeak-dev] The Trunk: Kernel-eem.1367.mcz In-Reply-To: References: Message-ID: <62C9EC8C-9208-4531-8B1B-197A195E4DB0@gmail.com> > On Mar 2, 2021, at 8:21 AM, Thiede, Christoph wrote: > >  > Hi Eliot, > > > > then I think there is an issue with the argument name. In #callPrimitive:, for example, it is named more specifically, maybePrimFailToken. In #doPrimitive:method:receiver:args:, we may feed it with the result of #tryPrimitive:withArgs: which can be anything, not only a context or fail token. > > > > Here is a second example: > > > > Object subclass: #ContextHack > > instanceVariableNames: '' > classVariableNames: '' > poolDictionaries: '' > category: 'CT-Experiments'. > ContextHack class compile: 'isArray > self error: #hacked'. > ContextHack new class "through" I still think that this is fuss over nothing. Even if the system did keep running with a Context that answered true to isArray it would have to have a stack pointer of 2 and a first arg/temp that was the PrimFailToken. You yourself complained of the performance of testing for the PrimFailToken. isArray is faster than objectClass == Array. We haven’t seen any issues with this. I suggest that if it ain’t broke we don’t fix it. > > Best, > Christoph > > Von: Squeak-dev im Auftrag von Eliot Miranda > Gesendet: Dienstag, 2. März 2021 16:27 Uhr > An: The general-purpose Squeak developers list > Betreff: Re: [squeak-dev] The Trunk: Kernel-eem.1367.mcz > > Hi Christoph, > >>> On Mar 2, 2021, at 5:17 AM, Thiede, Christoph wrote: >>> >>  >> Hi Eliot, >> >> >> >> thanks for the fix! Sorry for raising the same question again, but wouldn't it still be safer to dispense with the #isArray call here? It allows the simulated code to break out of the simulation by overriding #isArray anywhere. >> > > As I understand it no. The clue is in the variable name. contextOrPrimFailToken can only ever be a Context or an Array, so the send of isArray serves only to quickly differentiate between a Context and an Array. The message doesn’t get sent to any other kinds of object at that point so the concern that other classes may define isArray does not apply here. >> I think I posted a proof of concept here: http://forum.world.st/The-Trunk-Kernel-eem-1366-mcz-tp5126558p5126713.html :-) >> >> >> Best, >> Christoph >> Von: Squeak-dev im Auftrag von commits at source.squeak.org >> Gesendet: Dienstag, 2. Februar 2021 03:57:12 >> An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org >> Betreff: [squeak-dev] The Trunk: Kernel-eem.1367.mcz >> >> Eliot Miranda uploaded a new version of Kernel to project The Trunk: >> http://source.squeak.org/trunk/Kernel-eem.1367.mcz >> >> ==================== Summary ==================== >> >> Name: Kernel-eem.1367 >> Author: eem >> Time: 1 February 2021, 6:57:09.713484 pm >> UUID: def9aaa1-eb71-4da5-8f86-85856d9b88ad >> Ancestors: Kernel-eem.1366 >> >> Fix mistake in the previous commit. Thanks Levente! >> >> =============== Diff against Kernel-eem.1366 =============== >> >> Item was changed: >> ----- Method: Context>>isPrimFailToken: (in category 'private') ----- >> + isPrimFailToken: contextOrPrimFailToken >> + "Answer if contextOrPrimFailToken, which will either be a Context object or >> + a primitive fail token (a tuple of the PrimitiveFailToken unique object and >> + a primitive failure code), is the latter. This should only be used with the >> + (possibly indirect) results of Context>>doPrimitive:method:receiver:args:" >> + ^contextOrPrimFailToken isArray >> + and: [contextOrPrimFailToken size = 2 >> + and: [(contextOrPrimFailToken at: 1) == PrimitiveFailToken]]! >> - isPrimFailToken: anObject >> - ^(self objectClass: anObject) isArray >> - and: [anObject size = 2 >> - and: [(anObject at: 1) == PrimitiveFailToken]]! >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eliot.miranda at gmail.com Tue Mar 2 17:08:29 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Tue, 2 Mar 2021 09:08:29 -0800 Subject: [squeak-dev] The Trunk: CollectionsTests-dtl.350.mcz In-Reply-To: <1614686391666-0.post@n4.nabble.com> References: <1614686391666-0.post@n4.nabble.com> Message-ID: > On Mar 2, 2021, at 3:59 AM, Christoph Thiede wrote: > > Hi Dave, > > could there be something wrong with the ancestry of this version? The > notification email does not contain any visible diff and when updating my > image today, I got an MCEmptyDiffyVersion warning. +1 > > Best, > Christoph > > > > ----- > Carpe Squeak! > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 17:26:06 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 17:26:06 +0000 Subject: [squeak-dev] Merge Request: removeClass.cs Message-ID: <9c61ec35044a4b0abbcdc8b780abd47d@student.hpi.uni-potsdam.de> This changeset refactors the #removeClass logic (which has been upgraded by Marcel recently) and extracts it to SystemNavigation, analogously to System-ct.1221. It also refines the dialog to search for senders and subclasses of the class to remove as we know it from #removeMessage. [cid:21b5558d-d73d-4d2c-bcc4-eeb40f7dee49] Please merge or give me feedback for improvements. :-) Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: pastedImage.png Type: image/png Size: 23381 bytes Desc: pastedImage.png URL: From commits at source.squeak.org Tue Mar 2 18:16:42 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 18:16:42 0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1376.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1376.mcz ==================== Summary ==================== Name: Kernel-ct.1376 Author: ct Time: 2 March 2021, 7:16:36.10917 pm UUID: 4c5758e1-3727-f04b-86c3-e9fe79a65db4 Ancestors: Kernel-jar.1375 Adds #cull:cull:cull:cull:cull: (for five args) analogously to #value:value:value:value:. =============== Diff against Kernel-jar.1375 =============== Item was added: + ----- Method: BlockClosure>>cull:cull:cull:cull:cull: (in category 'evaluating') ----- + cull: firstArg cull: secondArg cull: thirdArg cull: fourthArg cull: fifthArg + "Activate the receiver, with five or less arguments." + "Handle the five argument case primitively" + + ^ numArgs + caseOf: { + [5] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg value: fifthArg]. + [4] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg]. + [3] -> [self value: firstArg value: secondArg value: thirdArg]. + [2] -> [self value: firstArg value: secondArg]. + [1] -> [self value: firstArg]. + [0] -> [self value] } + otherwise: [self numArgsError: numArgs]! Item was added: + ----- Method: FullBlockClosure>>cull:cull:cull:cull:cull: (in category 'evaluating') ----- + cull: firstArg cull: secondArg cull: thirdArg cull: fourthArg cull: fifthArg + "Activate the receiver, with five or less arguments." + "Handle the five argument case primitively" + + ^ numArgs + caseOf: { + [5] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg value: fifthArg]. + [4] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg]. + [3] -> [self value: firstArg value: secondArg value: thirdArg]. + [2] -> [self value: firstArg value: secondArg]. + [1] -> [self value: firstArg]. + [0] -> [self value] } + otherwise: [self numArgsError: numArgs]! Item was added: + ----- Method: MessageSend>>cull:cull:cull:cull:cull: (in category 'evaluating') ----- + cull: firstArg cull: secondArg cull: thirdArg cull: fourthArg cull: fifthArg + "Send the message with these optional arguments and answer the return value" + + ^ selector numArgs caseOf: { + [5] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg value: fifthArg]. + [4] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg]. + [3] -> [self value: firstArg value: secondArg value: thirdArg]. + [2] -> [self value: firstArg value: secondArg]. + [1] -> [self value: firstArg]. + [0] -> [self value] }! From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 2 18:17:38 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 2 Mar 2021 18:17:38 +0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1376.mcz In-Reply-To: References: Message-ID: Note that this does not only fill a logical gap but also could actually useful in MessageSendRecorder [1]. Best, Christoph [1] https://github.com/hpi-swa/MessageSendRecorder/blob/befc38911ab66cc810aaa03539ae7b6d8374c0b3/packages/MessageSendRecorder.package/MessageSendRecorder.class/instance/recordInto.return.receiver.arguments.context..st#L10 ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 2. März 2021 19:16:42 An: squeak-dev at lists.squeakfoundation.org Betreff: [squeak-dev] The Inbox: Kernel-ct.1376.mcz A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1376.mcz ==================== Summary ==================== Name: Kernel-ct.1376 Author: ct Time: 2 March 2021, 7:16:36.10917 pm UUID: 4c5758e1-3727-f04b-86c3-e9fe79a65db4 Ancestors: Kernel-jar.1375 Adds #cull:cull:cull:cull:cull: (for five args) analogously to #value:value:value:value:. =============== Diff against Kernel-jar.1375 =============== Item was added: + ----- Method: BlockClosure>>cull:cull:cull:cull:cull: (in category 'evaluating') ----- + cull: firstArg cull: secondArg cull: thirdArg cull: fourthArg cull: fifthArg + "Activate the receiver, with five or less arguments." + "Handle the five argument case primitively" + + ^ numArgs + caseOf: { + [5] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg value: fifthArg]. + [4] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg]. + [3] -> [self value: firstArg value: secondArg value: thirdArg]. + [2] -> [self value: firstArg value: secondArg]. + [1] -> [self value: firstArg]. + [0] -> [self value] } + otherwise: [self numArgsError: numArgs]! Item was added: + ----- Method: FullBlockClosure>>cull:cull:cull:cull:cull: (in category 'evaluating') ----- + cull: firstArg cull: secondArg cull: thirdArg cull: fourthArg cull: fifthArg + "Activate the receiver, with five or less arguments." + "Handle the five argument case primitively" + + ^ numArgs + caseOf: { + [5] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg value: fifthArg]. + [4] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg]. + [3] -> [self value: firstArg value: secondArg value: thirdArg]. + [2] -> [self value: firstArg value: secondArg]. + [1] -> [self value: firstArg]. + [0] -> [self value] } + otherwise: [self numArgsError: numArgs]! Item was added: + ----- Method: MessageSend>>cull:cull:cull:cull:cull: (in category 'evaluating') ----- + cull: firstArg cull: secondArg cull: thirdArg cull: fourthArg cull: fifthArg + "Send the message with these optional arguments and answer the return value" + + ^ selector numArgs caseOf: { + [5] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg value: fifthArg]. + [4] -> [self value: firstArg value: secondArg value: thirdArg value: fourthArg]. + [3] -> [self value: firstArg value: secondArg value: thirdArg]. + [2] -> [self value: firstArg value: secondArg]. + [1] -> [self value: firstArg]. + [0] -> [self value] }! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 2 23:18:26 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 2 Mar 2021 23:18:26 0000 Subject: [squeak-dev] The Trunk: Kernel-nice.1376.mcz Message-ID: Nicolas Cellier uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-nice.1376.mcz ==================== Summary ==================== Name: Kernel-nice.1376 Author: nice Time: 3 March 2021, 12:18:22.91462 am UUID: c9ee47c3-4e2a-fa4f-9dcd-ed61ababdb73 Ancestors: Kernel-jar.1375 Introduce hasLimitedPrecision which is the way to indicate that arithmetic may be inexact. =============== Diff against Kernel-jar.1375 =============== Item was added: + ----- Method: Float>>hasLimitedPrecision (in category 'testing') ----- + hasLimitedPrecision + ^true! Item was added: + ----- Method: Number>>hasLimitedPrecision (in category 'testing') ----- + hasLimitedPrecision + "indicate whether this number has limited precision. + Arithmetic involving numbers with limited precision is potentially inexact. + The default implementation is false. + Subclass subject to inexact arithmetic shall refine." + ^false! From commits at source.squeak.org Wed Mar 3 01:14:15 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 01:14:15 0000 Subject: [squeak-dev] The Trunk: Collections-nice.925.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.925.mcz ==================== Summary ==================== Name: Collections-nice.925 Author: nice Time: 3 March 2021, 2:14:13.09562 am UUID: ee92856e-98d1-3a41-a3f2-3529927e7a02 Ancestors: Collections-jar.924 Distinguish questionable LimitedPrecisionInterval (those with Float bounds or step) from ordinary Interval of Integer, Fraction or ScaledDecimals. The main interest of having a specific class is to avoid crippling Interval with Float workarounds, for the rare use case. Explain some of the pitfalls of LimitedPrecisionInterval, and encourage alternatives in class comment, which is a second advantage of having a separate class. Abandon fuzzy inclusion logic, which is considered to introduce more discrepancies than it tries to solve See http://bugs.squeak.org/view.php?id=6455. and method #testSurprisingFuzzyInclusion Fix two other failing tests for Interval of Floats. Fix size so that (0.3 to: 1.2 by: 0.1) includes: 1.2. See https://github.com/dolphinsmalltalk/Dolphin/issues/1108 This makes size a bit less performant than super, a 3rd reason why a specific class is neat. Huh, that's more comments than code ;). =============== Diff against Collections-jar.924 =============== Item was changed: ----- Method: Interval class>>from:to: (in category 'instance creation') ----- from: startInteger to: stopInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of 1." + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision]) + ifTrue: [LimitedPrecisionInterval] + ifFalse: [Interval]) basicNew - ^self basicNew setFrom: startInteger to: stopInteger by: 1! Item was changed: ----- Method: Interval class>>from:to:by: (in category 'instance creation') ----- from: startInteger to: stopInteger by: stepInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of stepNumber." + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision or: [stepInteger hasLimitedPrecision]]) + ifTrue: [LimitedPrecisionInterval] + ifFalse: [Interval]) basicNew - ^self basicNew setFrom: startInteger to: stopInteger by: stepInteger! Item was changed: ----- Method: Interval>>indexOf:startingAt: (in category 'accessing') ----- indexOf: anElement startingAt: startIndex "startIndex is an positive integer, the collection index where the search is started." - "during the computation of val , floats are only used when the receiver contains floats" + | index | - | index val | (self rangeIncludes: anElement) ifFalse: [ ^0 ]. + index := (anElement - start / step) rounded + 1. - val := anElement - self first / self increment. - val isFloat - ifTrue: [ - (val - val rounded) abs * 100000000 < 1 ifFalse: [ ^0 ]. - index := val rounded + 1 ] - ifFalse: [ - val isInteger ifFalse: [ ^0 ]. - index := val + 1 ]. - "finally, the value of startIndex comes into play:" (index between: startIndex and: self size) ifFalse: [ ^0 ]. + (self at: index) = anElement ifFalse: [ ^0 ]. ^index! Item was added: + Interval subclass: #LimitedPrecisionInterval + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Sequenceable'! + + !LimitedPrecisionInterval commentStamp: 'nice 3/3/2021 01:47' prior: 0! + A LimitedPrecisionInterval is an Interval whose bounds or step haveLimitedPrecision. + Due to inexact arithmetic, special precautions must be taken in the implementation, + in order to avoid unconsistent and surprising behavior as much as possible. + + Despite those efforts, LimitedPrecisionInterval is full of pitfalls. + It is recommended to avoid using LimitedPrecisionInterval unless understanding those pitfalls. + For example, (0.2 to: 0.6 by: 0.1) last = 0.5. + This interval does not includes 0.6 because (0.1*4+0.2) is slightly greater than 0.6. + Another example is that (0.2 to: 0.6 by: 0.1) does not include 0.3 but a Float slightly greater. + + A usual workaround is to use an Integer interval, and reconstruct the Float inside the loop. + For example: + (0 to: 4) collect: [:i | 0.1*i+0.2]. + or better if we want to have 0.3 and 0.6: + (2 to: 6) collect: [:i | i / 10.0]. + Another workaround is to not use limited precision at all, but Fraction or ScaledDecimal when possible: + (1/10 to: 7/10 by: 1/10). + (0.1s to: 0.7s by: 0.1s). + + Yet another pitfall is that optimized to:by:do: might differ from (to:by:) do: + In the former case, repeated addition of increment is used, in the later, a multiplication is used. + Observe the differences: + Array streamContents: [:str | 0 to: 3 by: 0.3 do: [:e | str nextPut: e]]. + Array streamContents: [:str | (0 to: 3 by: 0.3) do: [:e | str nextPut: e]]. + + There are many more discrepancies, so use carefully, or not use it at all.! Item was added: + ----- Method: LimitedPrecisionInterval>>copyFrom:to: (in category 'copying') ----- + copyFrom: startIndex to: stopIndex + startIndex = 1 ifTrue: [^super copyFrom: startIndex to: stopIndex]. + stopIndex < startIndex ifTrue: [^self copyEmpty]. + ^Array new: stopIndex - startIndex + 1 streamContents: [:stream | + startIndex to: stopIndex do: [:i | stream nextPut: (self at: i)]]! Item was added: + ----- Method: LimitedPrecisionInterval>>last (in category 'accessing') ----- + last + "Refer to the comment in SequenceableCollection|last." + + ^start + (step * (self size - 1))! Item was added: + ----- Method: LimitedPrecisionInterval>>reversed (in category 'converting') ----- + reversed + "There is no guaranty that super reversed would contain same elements. + Answer an Array instead" + + ^Array new: self size streamContents: [:stream | self reverseDo: [:each | stream nextPut: each]]! Item was added: + ----- Method: LimitedPrecisionInterval>>size (in category 'accessing') ----- + size + "Answer how many elements the receiver contains." + + | candidateSize | + candidateSize := (stop - start / step max: 0) rounded. + step > 0 + ifTrue: [candidateSize * step + start <= stop ifTrue: [^candidateSize + 1]] + ifFalse: [candidateSize * step + start >= stop ifTrue: [^candidateSize + 1]]. + ^candidateSize! From commits at source.squeak.org Wed Mar 3 01:19:00 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 01:19:00 0000 Subject: [squeak-dev] The Trunk: CollectionsTests-nice.351.mcz Message-ID: Nicolas Cellier uploaded a new version of CollectionsTests to project The Trunk: http://source.squeak.org/trunk/CollectionsTests-nice.351.mcz ==================== Summary ==================== Name: CollectionsTests-nice.351 Author: nice Time: 3 March 2021, 2:18:59.33262 am UUID: b5730ca8-f82f-3c44-af32-6b067a27d017 Ancestors: CollectionsTests-dtl.350 Change the expectations w.r.t. Interval fuzzy inclusion. Include a couple of tests taken from https://github.com/dolphinsmalltalk/Dolphin/issues/1108 Revise the expectedFailures, some turned into unexpected success! =============== Diff against CollectionsTests-dtl.350 =============== Item was changed: ----- Method: IntervalTest>>expectedFailures (in category 'failures') ----- expectedFailures + ^ #(testIntervalOfFloatEqual)! - ^ #(testIntervalOfFloatLast testIntervalOfFloatReversed testSurprisingFuzzyInclusionBehavior)! Item was added: + ----- Method: IntervalTest>>testElementOutOfBound (in category 'tests') ----- + testElementOutOfBound + self deny: ((1/5 to: 1.2 by: 1) anySatisfy: [:e | e > 1.2]).! Item was added: + ----- Method: IntervalTest>>testIncludesBound (in category 'tests') ----- + testIncludesBound + "This interval is crafted for including 1.2 + but a careless definition of size might exclude this bound" + self assert: (((0.3 to: 1.2 by: 0.1) includes: 1.2) ==> [(0.3 to: 1.2 by: 0.1) anySatisfy: [:each | each = 1.2]]).! Item was changed: ----- Method: IntervalTest>>testInclusionBug6455 (in category 'tests') ----- testInclusionBug6455 + "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455. + Well it's not a bug, and not a good feature. + See testSurprisingFuzzyInclusion for why this feature is not a good idea" - "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455 - It should work as long as Fuzzy inclusion test feature for Interval of Float is maintained. - This is a case when tested element is near ones of actual value, but by default. - Code used to work only in the case of close numbers by excess..." + self deny: ((0.2 to: 0.6 by: 0.1) includes: 0.3) description: 'Strict Float equality expecation is too high'. + self assert: ((0.2 to: 0.6 by: 0.1) includes: 0.3 successor) description: 'it includes a slightly different number'! - self assert: ((0 to: Float pi by: Float pi / 100) includes: Float pi * (3/100))! Item was changed: ----- Method: IntervalTest>>testIndexOfBug6455 (in category 'tests') ----- testIndexOfBug6455 "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455 + Well it's not a bug, and not a good feature. + See testSurprisingFuzzyInclusion for why this feature is not a good idea" - It should work as long as Fuzzy inclusion test feature for Interval of Float is maintained. - This is a case when tested element is near ones of actual value, but by default. - Code used to work only in the case of close numbers by excess..." + self deny: ((0.2 to: 0.6 by: 0.1) indexOf: 0.3) = 2 description: 'Strict Float equality expecation is too high'. + self assert: ((0.2 to: 0.6 by: 0.1) indexOf: 0.3 successor) = 2 description: 'it includes a slightly different number'! - self assert: ((0 to: Float pi by: Float pi / 100) indexOf: Float pi * (3/100)) = 4! From commits at source.squeak.org Wed Mar 3 07:04:40 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 07:04:40 0000 Subject: [squeak-dev] The Trunk: PreferenceBrowser-mt.113.mcz Message-ID: Marcel Taeumel uploaded a new version of PreferenceBrowser to project The Trunk: http://source.squeak.org/trunk/PreferenceBrowser-mt.113.mcz ==================== Summary ==================== Name: PreferenceBrowser-mt.113 Author: mt Time: 3 March 2021, 8:04:40.386712 am UUID: ae453663-399c-804e-9c2e-df714093e1d6 Ancestors: PreferenceBrowser-mt.112, PreferenceBrowser-ct.101 Merge fix for preferences tool to honor "open attached to mouse" preference. =============== Diff against PreferenceBrowser-mt.112 =============== Item was changed: ----- Method: PreferenceBrowser class>>open (in category 'instance creation') ----- open | browser | browser := self new. (PreferenceBrowserMorph withModel: browser) + openAsTool. - openInWorld. ^browser. ! Item was changed: ----- Method: PreferenceBrowser>>initialize (in category 'initialize-release') ----- initialize + super initialize. preferences := Preferences. title := 'Preference Browser'.! Item was changed: ----- Method: PreferenceBrowserMorph>>initializeWithModel: (in category 'initialization') ----- initializeWithModel: aPreferenceBrowser lastKeystrokeTime := 0. lastKeystrokes := ''. self hResizing: #spaceFill; "Snap #extent to grid if enabled. See #worldGridEnabled." vResizing: #spaceFill; "Snap #extent to grid if enabled. See #worldGridEnabled." model: aPreferenceBrowser; setLabel: self model windowTitle; name: 'PreferenceBrowser'; addMorph: self rootPanel fullFrame: self rootPanelLayoutFrame; + addMorph: self newButtonRow fullFrame: self buttonRowLayoutFrame; + "Set bounds like the MorphicToolBuilder does when building windows." + bounds: (RealEstateAgent + initialFrameFor: self + initialExtent: aPreferenceBrowser initialExtent + world: self currentWorld).! - addMorph: self newButtonRow fullFrame: self buttonRowLayoutFrame.! From commits at source.squeak.org Wed Mar 3 07:05:09 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 07:05:09 0000 Subject: [squeak-dev] The Trunk: PreferenceBrowser-ct.101.mcz Message-ID: Marcel Taeumel uploaded a new version of PreferenceBrowser to project The Trunk: http://source.squeak.org/trunk/PreferenceBrowser-ct.101.mcz ==================== Summary ==================== Name: PreferenceBrowser-ct.101 Author: ct Time: 31 December 2019, 3:20:07.412022 am UUID: 2a3197c6-9d2f-9b44-90b6-f73b221b3e54 Ancestors: PreferenceBrowser-mt.97 Honor #openToolsAttachedToMouseCursor when opening the PreferenceBrowser =============== Diff against PreferenceBrowser-mt.97 =============== Item was changed: ----- Method: PreferenceBrowser class>>open (in category 'instance creation') ----- open | browser | browser := self new. (PreferenceBrowserMorph withModel: browser) + openAsTool. - openInWorld. ^browser. ! Item was changed: ----- Method: PreferenceBrowser>>initialize (in category 'initialize-release') ----- initialize + super initialize. preferences := Preferences. title := 'Preference Browser'.! Item was changed: ----- Method: PreferenceBrowserMorph>>initializeWithModel: (in category 'initialization') ----- initializeWithModel: aPreferenceBrowser lastKeystrokeTime := 0. lastKeystrokes := ''. self model: aPreferenceBrowser; setLabel: self model windowTitle; name: 'PreferenceBrowser'; addMorph: self rootPanel fullFrame: self rootPanelLayoutFrame; + addMorph: self newButtonRow fullFrame: self buttonRowLayoutFrame; + extent: aPreferenceBrowser initialExtent.! - addMorph: self newButtonRow fullFrame: self buttonRowLayoutFrame.! From marcel.taeumel at hpi.de Wed Mar 3 09:18:52 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 3 Mar 2021 10:18:52 +0100 Subject: [squeak-dev] Merge Request: removeClass.cs In-Reply-To: <9c61ec35044a4b0abbcdc8b780abd47d@student.hpi.uni-potsdam.de> References: <9c61ec35044a4b0abbcdc8b780abd47d@student.hpi.uni-potsdam.de> Message-ID: Hmm... tricky. :-) Here is the current one: - Could you keep the title and add the prefixes "yes" or "no" before the options? - What is your preferred way of having line breaks in the text? Here is the current remove-selector dialog: ... Well, this does not scale at all. What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. [Yes] [No]  <--- SPACE---> [More...] Best, Marcel Am 02.03.2021 18:26:16 schrieb Thiede, Christoph : This changeset refactors the #removeClass logic (which has been upgraded by Marcel recently) and extracts it to SystemNavigation, analogously to System-ct.1221. It also refines the dialog to search for senders and subclasses of the class to remove as we know it from #removeMessage. Please merge or give me feedback for improvements. :-) Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 28990 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 20780 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: pastedImage.png Type: image/png Size: 23381 bytes Desc: not available URL: From commits at source.squeak.org Wed Mar 3 09:34:47 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 09:34:47 0000 Subject: [squeak-dev] The Trunk: CollectionsTests-nice.352.mcz Message-ID: Nicolas Cellier uploaded a new version of CollectionsTests to project The Trunk: http://source.squeak.org/trunk/CollectionsTests-nice.352.mcz ==================== Summary ==================== Name: CollectionsTests-nice.352 Author: nice Time: 3 March 2021, 10:34:45.83962 am UUID: 8666dc7b-f181-6340-97d4-be3d5a50166d Ancestors: CollectionsTests-nice.351 Separate the Interval of Float tests into LimitedPrecisionIntervalTest. Document a few more invalid expectations related to inexact nature of arithmetic on LimitedPrecisionInterval. =============== Diff against CollectionsTests-nice.351 =============== Item was removed: - ----- Method: IntervalTest>>expectedFailures (in category 'failures') ----- - expectedFailures - - ^ #(testIntervalOfFloatEqual)! Item was changed: ----- Method: IntervalTest>>testAsIntervalWithFractionalProgression (in category 'tests') ----- testAsIntervalWithFractionalProgression self assert: (1 to: 2 by: 1/2) equals: ({1. 3/2. 2} as: Interval). + self assert: (1 to: 2 by: 0.2s) equals: ({1. 1.2s. 1.4s. 1.6s. 1.8s. 2} as: Interval).! - self assert: (1 to: 2 by: 0.2s) equals: ({1. 1.2s. 1.4s. 1.6s. 1.8s. 2} as: Interval). - - self should: [#(0.1 0.2 0.3 0.4) as: Interval] - raise: Error - description: 'There is no guaranty that Interval of Float can be constructed from individual Float'. - "Even though, by chance there might be a Float Interval with same elements" - #(0.1 0.2 0.3 0.4) hasEqualElements: (0.1 to: 0.4 by: 0.1 predecessor)! Item was added: + ----- Method: IntervalTest>>testCollect (in category 'tests') ----- + testCollect + | s i | + i := (10 to: 20). + s := i collect: [:e | e]. + self assert: (s hasEqualElements: i)! Item was removed: - ----- Method: IntervalTest>>testElementOutOfBound (in category 'tests') ----- - testElementOutOfBound - self deny: ((1/5 to: 1.2 by: 1) anySatisfy: [:e | e > 1.2]).! Item was removed: - ----- Method: IntervalTest>>testIncludesBound (in category 'tests') ----- - testIncludesBound - "This interval is crafted for including 1.2 - but a careless definition of size might exclude this bound" - self assert: (((0.3 to: 1.2 by: 0.1) includes: 1.2) ==> [(0.3 to: 1.2 by: 0.1) anySatisfy: [:each | each = 1.2]]).! Item was removed: - ----- Method: IntervalTest>>testInclusion (in category 'tests') ----- - testInclusion - "Non regression test for another bug of fuzzy inclusion" - - self deny: ((1.0 to: 3.0 by: 1.0 successor) includes: 3.0) description: 'The last element of this Interval is closed to 2'! Item was removed: - ----- Method: IntervalTest>>testInclusionBug6455 (in category 'tests') ----- - testInclusionBug6455 - "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455. - Well it's not a bug, and not a good feature. - See testSurprisingFuzzyInclusion for why this feature is not a good idea" - - self deny: ((0.2 to: 0.6 by: 0.1) includes: 0.3) description: 'Strict Float equality expecation is too high'. - self assert: ((0.2 to: 0.6 by: 0.1) includes: 0.3 successor) description: 'it includes a slightly different number'! Item was removed: - ----- Method: IntervalTest>>testIndexOfBug6455 (in category 'tests') ----- - testIndexOfBug6455 - "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455 - Well it's not a bug, and not a good feature. - See testSurprisingFuzzyInclusion for why this feature is not a good idea" - - self deny: ((0.2 to: 0.6 by: 0.1) indexOf: 0.3) = 2 description: 'Strict Float equality expecation is too high'. - self assert: ((0.2 to: 0.6 by: 0.1) indexOf: 0.3 successor) = 2 description: 'it includes a slightly different number'! Item was removed: - ----- Method: IntervalTest>>testInfiniteLoopBug6456 (in category 'tests') ----- - testInfiniteLoopBug6456 - "This is a non regression test against mantis bug #6456. - Some Float interval size was not consistent with do: loop. - Some Float Interval used to do: infinite loops" - - | x interval counter size | - x := (1.0 timesTwoPower: Float precision). "Note: x+1 = x due to inexact arithmetic" - interval := x to: x+4. - size := interval size. - counter := 0. - interval do: [:each | self assert: (counter := counter + 1) <= size].! Item was removed: - ----- Method: IntervalTest>>testIntervalOfFloatEqual (in category 'tests') ----- - testIntervalOfFloatEqual - "Interval with Float are weirdos" - - | interval1 interval2 interval3 interval4 | - interval1 := (0 to: 1 by: 1/10). - interval2 := (0.0 to: 1 by: 1/10). - self deny: (interval1 = interval2) ==> (interval1 hasEqualElements: interval2) - description: 'Interval of Float may have different elements from another Interval, even if they pretend to be equal.'. - - interval3 := (0.3 to: 0.6 by: 1/10). - interval4 := (0.3 to: 0.6 by: 0.1). - self deny: (interval3 hasEqualElements: interval4) ==> (interval3 = interval4) - description: 'Interval of Float may pretend they differ from another Interval even if they have same elements.'.! Item was removed: - ----- Method: IntervalTest>>testIntervalOfFloatLast (in category 'tests') ----- - testIntervalOfFloatLast - "Some definition of last were problematic for Interval of Float" - - | increment upperBound interval | - self assert: (0.2 to: 0.9 by: 0.1) last = (0.2 to: 0.9 by: 0.1) asArray last - description: 'the last element cannot reasonably change when converting asArray'. - - upperBound := 1.7. - increment := 0.1. - self deny: (0 to: upperBound by: increment) last > upperBound - description: 'the last element cannot reasonably exceed upper bound'. - - interval := -0.9999999999999994 to: 1 by: 2. - self assert: interval last < interval first - ==> (interval isEmpty or: [interval increment < 0]) - description: 'the last element cannot reasonably deceed(*) lower bound (* be inferior to)'! Item was removed: - ----- Method: IntervalTest>>testIntervalOfFloatReversed (in category 'tests') ----- - testIntervalOfFloatReversed - self assert: (-16.3 to: 20.1 by: 1.3) reversed size - equals: (-16.3 to: 20.1 by: 1.3) size - description: 'reversed should preserve the size of a collection'. - self assert: (0.1 to: 0.9 by: 0.1) reversed asArray - equals: (0.1 to: 0.9 by: 0.1) asArray reversed - description: 'reversed should preserve the elements of a collection'.! Item was changed: ----- Method: IntervalTest>>testPermutationsDo (in category 'tests') ----- testPermutationsDo | i oc | + i := (4 to: 13 by: 3). - i := (1.234 to: 4.234). oc := OrderedCollection new. + i permutationsDo: [:e | oc add: e copy]. + self assert: oc size = i size factorial. + self assert: oc asSet size = oc size. + self assert: (oc allSatisfy: [:e | e sorted hasEqualElements: i]). - i permutationsDo: [:e | oc add: e]. - self assert: (oc size = i size factorial). ^ oc! Item was changed: ----- Method: IntervalTest>>testRangeIncludes (in category 'tests') ----- testRangeIncludes + self assert: ((1 to: 10) rangeIncludes: 4) description: '4 is within this range'. + self assert: ((1 to: 10 by: 2) rangeIncludes: 4) description: 'even if the interval does not include 4'. + self deny: ((1 to: 10 by: -1) rangeIncludes: 4) description: 'this range is empty'. + self assert: ((10 to: 1 by: -4) rangeIncludes: 4) description: 'the range can be retrograde'. + self assert: ((1 to: 10) rangeIncludes: 10) description: 'the range includes the bounds'. + self assert: ((1 to: 10 by: 2) rangeIncludes: 10) description: 'even when bound lies past the last element'. + #(0 11) do: [:outOfBound | + #(-2 -1 2 2) do: [:step | + self deny: ((1 to: 10 by: step) includes: outOfBound)]]! - self - assert: ((1 to: 10) - rangeIncludes: 3). - self - assert: ((1 to: 10 by: 2) - rangeIncludes: 3). - self - deny: ((1 to: 10) - rangeIncludes: 0). - self - deny: ((1 to: 10) - rangeIncludes: 11). - self - deny: ((1 to: 10 by: 2) - rangeIncludes: 0). - self - deny: ((1 to: 10 by: 2) - rangeIncludes: 11)! Item was removed: - ----- Method: IntervalTest>>testSurprisingFuzzyInclusionBehavior (in category 'tests') ----- - testSurprisingFuzzyInclusionBehavior - "If ever Interval implement fuzzy inclusion, then we can expect weird logic..." - self assert: ((0.1 to: 0.9 by: 0.1) includes: 0.3) - ==> (((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) > 0) - description: 'A Collection that includes something has at least one occurrence of something'. - self assert: ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) - >= ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) - description: 'The last index of an object in a SequenceableCollection should be greater than or equal to the first index'. - self assert: ((0.1 to: 0.9 by: 0.1) includes: 0.3) - ==> (((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) size < (0.1 to: 0.9 by: 0.1) size) - description: 'A Collection should be able to shrink by stripping own elements'.! Item was added: + ClassTestCase subclass: #LimitedPrecisionIntervalTest + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'CollectionsTests-Sequenceable'! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>assert:is:withinUlp: (in category 'asserting - extensions') ----- + assert: aFloat is: anotherFloat withinUlp: anInteger + ^self assert: (aFloat - anotherFloat) abs <= (aFloat ulp * anInteger)! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>expectedFailures (in category 'failures') ----- + expectedFailures + + ^ #(testIntervalOfFloatEqual)! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testAdd (in category 'tests') ----- + testAdd + | floatInterval | + floatInterval := (0.3 to: 0.6 by: 0.1). + self deny: floatInterval size = (floatInterval + 1) size description: 'there is no guaranty that size is preserved by arithmetic operation'! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testAsIntervalWithFractionalProgression (in category 'tests') ----- + testAsIntervalWithFractionalProgression + self should: [#(0.1 0.2 0.3 0.4) as: Interval] + raise: Error + description: 'There is no guaranty that Interval of Float can be constructed from individual Float'. + "Even though, by chance there might be a Float Interval with same elements" + #(0.1 0.2 0.3 0.4) hasEqualElements: (0.1 to: 0.4 by: 0.1 predecessor)! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testCollect (in category 'tests') ----- + testCollect + | s i | + i := (0.1 to: 1.0 by: 0.1). + s := i collect: [:e | e]. + self assert: (s hasEqualElements: i)! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testDo (in category 'tests') ----- + testDo + | s i | + s := OrderedCollection new. + i := (0.1 to: 1.0 by: 0.1). + i do: [ :each | s addLast: each]. + self assert: (s hasEqualElements: i)! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testElementOutOfBound (in category 'tests') ----- + testElementOutOfBound + "Note: this is a test for correct implementation of size. + With super definition of size, an element past the bound could be included" + + self deny: ((1/5 to: 1.2 by: 1) anySatisfy: [:e | e > 1.2]).! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testIncludesBound (in category 'tests') ----- + testIncludesBound + "This interval is crafted for including 1.2 + but a careless definition of size might exclude this bound" + self assert: (((0.3 to: 1.2 by: 0.1) includes: 1.2) ==> [(0.3 to: 1.2 by: 0.1) anySatisfy: [:each | each = 1.2]]).! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testInclusion (in category 'tests') ----- + testInclusion + "Non regression test for another bug of fuzzy inclusion" + + self deny: ((1.0 to: 3.0 by: 1.0 successor) includes: 3.0) description: 'The last element of this Interval is closed to 2'! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testInclusionBug6455 (in category 'tests') ----- + testInclusionBug6455 + "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455. + Well it's not a bug, and not a good feature. + See testSurprisingFuzzyInclusion for why this feature is not a good idea" + + self deny: ((0.2 to: 0.6 by: 0.1) includes: 0.3) description: 'Strict Float equality expecation is too high'. + self assert: ((0.2 to: 0.6 by: 0.1) includes: 0.3 successor) description: 'it includes a slightly different number'! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testIndexOfBug6455 (in category 'tests') ----- + testIndexOfBug6455 + "This test is about mantis bug http://bugs.squeak.org/view.php?id=6455 + Well it's not a bug, and not a good feature. + See testSurprisingFuzzyInclusion for why this feature is not a good idea" + + self deny: ((0.2 to: 0.6 by: 0.1) indexOf: 0.3) = 2 description: 'Strict Float equality expecation is too high'. + self assert: ((0.2 to: 0.6 by: 0.1) indexOf: 0.3 successor) = 2 description: 'it includes a slightly different number'! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testInfiniteLoopBug6456 (in category 'tests') ----- + testInfiniteLoopBug6456 + "This is a non regression test against mantis bug #6456. + Some Float interval size was not consistent with do: loop. + Some Float Interval used to do: infinite loops" + + | x interval counter size | + x := (1.0 timesTwoPower: Float precision). "Note: x+1 = x due to inexact arithmetic" + interval := x to: x+4. + size := interval size. + counter := 0. + interval do: [:each | self assert: (counter := counter + 1) <= size].! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testIntervalOfFloatEqual (in category 'tests') ----- + testIntervalOfFloatEqual + "Interval with Float are weirdos" + + | interval1 interval2 interval3 interval4 | + interval1 := (0 to: 1 by: 1/10). + interval2 := (0.0 to: 1 by: 1/10). + self deny: (interval1 = interval2) ==> (interval1 hasEqualElements: interval2) + description: 'Interval of Float may have different elements from another Interval, even if they pretend to be equal.'. + + interval3 := (0.3 to: 0.6 by: 1/10). + interval4 := (0.3 to: 0.6 by: 0.1). + self deny: (interval3 hasEqualElements: interval4) ==> (interval3 = interval4) + description: 'Interval of Float may pretend they differ from another Interval even if they have same elements.'.! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testLast (in category 'tests') ----- + testLast + "Some definition of last were problematic for Interval of Float" + + | increment upperBound interval | + self assert: (0.2 to: 0.9 by: 0.1) last = (0.2 to: 0.9 by: 0.1) asArray last + description: 'the last element cannot reasonably change when converting asArray'. + + upperBound := 1.7. + increment := 0.1. + self deny: (0 to: upperBound by: increment) last > upperBound + description: 'the last element cannot reasonably exceed upper bound'. + + interval := -0.9999999999999994 to: 1 by: 2. + self assert: interval last < interval first + ==> (interval isEmpty or: [interval increment < 0]) + description: 'the last element cannot reasonably deceed(*) lower bound (* be inferior to)'! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testReversed (in category 'tests') ----- + testReversed + self assert: (-16.3 to: 20.1 by: 1.3) reversed size + equals: (-16.3 to: 20.1 by: 1.3) size + description: 'reversed should preserve the size of a collection'. + self assert: (0.1 to: 0.9 by: 0.1) reversed asArray + equals: (0.1 to: 0.9 by: 0.1) asArray reversed + description: 'reversed should preserve the elements of a collection'.! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testSum (in category 'tests') ----- + testSum + | floatInterval | + floatInterval := 0.1 to: 1.0 by: 0.1. + self deny: floatInterval sum = floatInterval asArray sum description: 'do not expect strict Float equality after arithmetic operations'. + self assert: floatInterval sum is: floatInterval asArray sum withinUlp: floatInterval size / 2! Item was added: + ----- Method: LimitedPrecisionIntervalTest>>testSurprisingFuzzyInclusionBehavior (in category 'tests') ----- + testSurprisingFuzzyInclusionBehavior + "If ever Interval implement fuzzy inclusion, then we can expect weird logic..." + self assert: ((0.1 to: 0.9 by: 0.1) includes: 0.3) + ==> (((0.1 to: 0.9 by: 0.1) occurrencesOf: 0.3) > 0) + description: 'A Collection that includes something has at least one occurrence of something'. + self assert: ((0.1 to: 0.9 by: 0.1) lastIndexOf: 0.3) + >= ((0.1 to: 0.9 by: 0.1) indexOf: 0.3) + description: 'The last index of an object in a SequenceableCollection should be greater than or equal to the first index'. + self assert: ((0.1 to: 0.9 by: 0.1) includes: 0.3) + ==> (((0.1 to: 0.9 by: 0.1) copyWithout: 0.3) size < (0.1 to: 0.9 by: 0.1) size) + description: 'A Collection should be able to shrink by stripping own elements'.! From commits at source.squeak.org Wed Mar 3 09:46:03 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 09:46:03 0000 Subject: [squeak-dev] The Trunk: Collections-nice.926.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.926.mcz ==================== Summary ==================== Name: Collections-nice.926 Author: nice Time: 3 March 2021, 10:46:01.17162 am UUID: bb5d2ec0-d044-c54f-9e8a-5442626c7573 Ancestors: Collections-nice.925 Fix LimitedPrecisionInterval>>collect: it should avoid accumulating increments which also accumulates rounding errors and make collect: behavior diverge from do:. Rather than modifying Interval>>collect:, implement the specific inexact arithmetic handling in specific subclass. Do the same with do: and reverseDo:. This enables restoring the legacy Interval enumerations which perform only one operation per loop instead of two. Do not check rangeIncludes: in indexOf:startingAt:. This is useless foe exact Interval, and now redundant for LimitedPrecisionInterval thanks to more carefull implementation of #size. =============== Diff against Collections-nice.925 =============== Item was changed: ----- Method: Interval>>do: (in category 'enumerating') ----- + do: aBlock + + | aValue | + aValue := start. + step < 0 + ifTrue: [[stop <= aValue] + whileTrue: + [aBlock value: aValue. + aValue := aValue + step]] + ifFalse: [[stop >= aValue] + whileTrue: + [aBlock value: aValue. + aValue := aValue + step]]! - do: aBlock - "Evaluate aBlock for each value of the interval. - Implementation note: instead of repeatedly incrementing the value - aValue := aValue + step. - until stop is reached, - We prefer to recompute value from start - aValue := start + (index * step). - This is better for floating points accuracy, while not degrading Integer and Fraction speed too much. - Moreover, this is consistent with methods #at: and #size" - - | aValue index size | - index := 0. - size := self size. - [index < size] - whileTrue: [aValue := start + (index * step). - index := index + 1. - aBlock value: aValue]! Item was changed: ----- Method: Interval>>indexOf:startingAt: (in category 'accessing') ----- indexOf: anElement startingAt: startIndex "startIndex is an positive integer, the collection index where the search is started." | index | - (self rangeIncludes: anElement) ifFalse: [ ^0 ]. index := (anElement - start / step) rounded + 1. (index between: startIndex and: self size) ifFalse: [ ^0 ]. (self at: index) = anElement ifFalse: [ ^0 ]. ^index! Item was changed: ----- Method: Interval>>reverseDo: (in category 'enumerating') ----- reverseDo: aBlock + "Evaluate aBlock for each element of my interval, in reverse order." + | aValue | + aValue := self last. + step < 0 + ifTrue: [[start >= aValue] + whileTrue: [aBlock value: aValue. + aValue := aValue - step]] + ifFalse: [[start <= aValue] + whileTrue: [aBlock value: aValue. + aValue := aValue - step]]! - "Evaluate aBlock for each element of my interval, in reverse order. - Implementation notes: see do: for an explanation on loop detail" - - | aValue index | - index := self size. - [index > 0] - whileTrue: [ - index := index - 1. - aValue := start + (index * step). - aBlock value: aValue]! Item was added: + ----- Method: LimitedPrecisionInterval>>collect: (in category 'enumerating') ----- + collect: aBlock + "Evaluate aBlock with each of the receiver's elements as the argument. + Collect the resulting values into a collection like the receiver. Answer + the new collection. + Implementation notes: see do: for an explanation on loop detail" + | result | + result := self species new: self size. + 1 to: result size do: + [:i | + "(self at: i) is inlined here to avoid repeated bound checking" + result at: i put: i - 1 * step + start]. + ^ result! Item was added: + ----- Method: LimitedPrecisionInterval>>do: (in category 'enumerating') ----- + do: aBlock + "Evaluate aBlock for each value of the interval. + Implementation note: instead of repeatedly incrementing the value + aValue := aValue + step. + until stop is reached, + We prefer to recompute value from start + aValue := start + (index * step). + This is better for floating points accuracy, while not degrading Integer and Fraction speed too much. + Moreover, this is consistent with methods #at: and #size" + + | aValue index size | + index := 0. + size := self size. + [index < size] + whileTrue: [aValue := start + (index * step). + index := index + 1. + aBlock value: aValue]! Item was added: + ----- Method: LimitedPrecisionInterval>>reverseDo: (in category 'enumerating') ----- + reverseDo: aBlock + "Evaluate aBlock for each element of my interval, in reverse order. + Implementation notes: see do: for an explanation on loop detail" + + | aValue index | + index := self size. + [index > 0] + whileTrue: [ + index := index - 1. + aValue := start + (index * step). + aBlock value: aValue]! From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 3 11:13:25 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 3 Mar 2021 11:13:25 +0000 Subject: [squeak-dev] Merge Request: removeClass.cs In-Reply-To: References: <9c61ec35044a4b0abbcdc8b780abd47d@student.hpi.uni-potsdam.de>, Message-ID: <50a5273d783648e984dd1d91c8b52bfd@student.hpi.uni-potsdam.de> Hi Marcel, thanks for the feedback! > Could you keep the title Good catch! That functionality is not provided at the moment by UIManager>>#chooseFrom:.... We would need to extend the UIManager protocol first. Which I would actually dislike to do because it's finally time to implement a proper UserNotification hierarchy instead. I'm looking really forward to tackle this one soon! :-) > and add the prefixes "yes" or "no" before the options? Hm, but wouldn't this make the labels even longer and harder to read? Also, I intended to avoid generic yes/no labels as also recommended by the Win32 UX Guidelines [1], for example. Isn't it rather a good thing to force the user to think about the action they are going to select before they do the wrong thing by accident? (The same discussion could apply to the standard "Is it OK to discard" dialog. I have seen multiple Squeak newbies, including myself, that were remarkably confused by the semantics of this dialog. I would vote for redesigning this dialog, too, by the way. :-)) > What is your preferred way of having line breaks in the text? My preferred way would be to defer this job to the UIManager implementation (more concretely: DialogWindow), finally. It just feels wrong to hack this into every domain-specific notificator, and different font sizes/styles are not honored at all at the moment. Auto line-breaking could try to break the text into an approximately squared shape, similar to what Microsoft Windows and probably other window managers are doing. But this would require some trial- and failure or approximation logic in the UI implementation, I guess. > What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. Rather not, if possible. :-) I use the browse options very often (except the "sorry I asked" one) and it would be a shame to spend a second click for it. And reduce visibility. We could also make use of links inside the text, but this would be a downgrade as well since they do not support proper keyboard navigation. Also, clicking a link would not close the dialog automatically. What do you think? Are four buttons really too much? :-) Best, Christoph [1] https://docs.microsoft.com/en-us/windows/win32/uxguide/win-dialog-box#commit-buttons:~:text=Responding%20to%20main%20instructions ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 3. März 2021 10:18:52 An: squeak-dev Betreff: Re: [squeak-dev] Merge Request: removeClass.cs Hmm... tricky. :-) Here is the current one: [cid:6ab47abe-1e5c-494a-840d-b25a59cb71a5] - Could you keep the title and add the prefixes "yes" or "no" before the options? - What is your preferred way of having line breaks in the text? Here is the current remove-selector dialog: [cid:75ebde4b-b7dd-45dc-b2a6-15f70ec12617] ... Well, this does not scale at all. What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. [Yes] [No] <--- SPACE---> [More...] Best, Marcel Am 02.03.2021 18:26:16 schrieb Thiede, Christoph : This changeset refactors the #removeClass logic (which has been upgraded by Marcel recently) and extracts it to SystemNavigation, analogously to System-ct.1221. It also refines the dialog to search for senders and subclasses of the class to remove as we know it from #removeMessage. [cid:21b5558d-d73d-4d2c-bcc4-eeb40f7dee49] Please merge or give me feedback for improvements. :-) Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 28990 bytes Desc: image.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 20780 bytes Desc: image.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: pastedImage.png Type: image/png Size: 23381 bytes Desc: pastedImage.png URL: From marcel.taeumel at hpi.de Wed Mar 3 11:17:27 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 3 Mar 2021 12:17:27 +0100 Subject: [squeak-dev] Merge Request: removeClass.cs In-Reply-To: <50a5273d783648e984dd1d91c8b52bfd@student.hpi.uni-potsdam.de> References: <9c61ec35044a4b0abbcdc8b780abd47d@student.hpi.uni-potsdam.de> <,> <50a5273d783648e984dd1d91c8b52bfd@student.hpi.uni-potsdam.de> Message-ID: > Hm, but wouldn't this make the labels even longer and harder to read?  Let me rephrase. The current labels are way too wordy. They should, however, start with a simple "Yes" or "No", followed by a compact explanation of what else happens when users click the button. Given that the title reads "Remove class", the buttons could be: [Yes] [Yes, and browse references] [No] [No, but browse references] Best, Marcel Am 03.03.2021 12:13:37 schrieb Thiede, Christoph : Hi Marcel, [http://www.hpi.de/] thanks for the feedback! > Could you keep the title Good catch! That functionality is not provided at the moment by UIManager>>#chooseFrom:.... We would need to extend the UIManager protocol first. Which I would actually dislike to do because it's finally time to implement a proper UserNotification hierarchy instead. I'm looking really forward to tackle this one soon! :-) > and add the prefixes "yes" or "no" before the options? Hm, but wouldn't this make the labels even longer and harder to read? Also, I intended to avoid generic yes/no labels as also recommended by the Win32 UX Guidelines [1], for example. Isn't it rather a good thing to force the user to think about the action they are going to select before they do the wrong thing by accident? (The same discussion could apply to the standard "Is it OK to discard" dialog. I have seen multiple Squeak newbies, including myself, that were remarkably confused by the semantics of this dialog. I would vote for redesigning this dialog, too, by the way. :-)) > What is your preferred way of having line breaks in the text? My preferred way would be to defer this job to the UIManager implementation (more concretely: DialogWindow), finally. It just feels wrong to hack this into every domain-specific notificator, and different font sizes/styles are not honored at all at the moment. Auto line-breaking could try to break the text into an approximately squared shape, similar to what Microsoft Windows and probably other window managers are doing. But this would require some trial- and failure or approximation logic in the UI implementation, I guess. > What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. Rather not, if possible. :-) I use the browse options very often (except the "sorry I asked" one) and it would be a shame to spend a second click for it. And reduce visibility. We could also make use of links inside the text, but this would be a downgrade as well since they do not support proper keyboard navigation. Also, clicking a link would not close the dialog automatically. What do you think? Are four buttons really too much? :-) Best, Christoph [1] https://docs.microsoft.com/en-us/windows/win32/uxguide/win-dialog-box#commit-buttons:~:text=Responding%20to%20main%20instructions [https://docs.microsoft.com/en-us/windows/win32/uxguide/win-dialog-box#commit-buttons:~:text=Responding%20to%20main%20instructions] Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 3. März 2021 10:18:52 An: squeak-dev Betreff: Re: [squeak-dev] Merge Request: removeClass.cs   Hmm... tricky. :-) Here is the current one: - Could you keep the title and add the prefixes "yes" or "no" before the options? - What is your preferred way of having line breaks in the text? Here is the current remove-selector dialog: ... Well, this does not scale at all. What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. [Yes] [No]  <--- SPACE---> [More...] Best, Marcel Am 02.03.2021 18:26:16 schrieb Thiede, Christoph : This changeset refactors the #removeClass logic (which has been upgraded by Marcel recently) and extracts it to SystemNavigation, analogously to System-ct.1221. It also refines the dialog to search for senders and subclasses of the class to remove as we know it from #removeMessage. Please merge or give me feedback for improvements. :-) Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 28990 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 20780 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: pastedImage.png Type: image/png Size: 23381 bytes Desc: not available URL: From lewis at mail.msen.com Wed Mar 3 13:08:34 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Wed, 3 Mar 2021 08:08:34 -0500 Subject: [squeak-dev] What about "self currentProject"? In-Reply-To: References: Message-ID: <20210303130834.GA31385@shell.msen.com> On Tue, Mar 02, 2021 at 10:03:02AM +0100, Marcel Taeumel wrote: > Hi all! > > After typing "Project current" for the n-th time, I was wondering, whether "self currentProject" could be a nice little idiom for the Squeak environment.?? > > We had several thoughts on this matter: > http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072 [http://forum.world.st/Object-gt-gt-currentProjectWorld-td5044161.html#a5045072] > > http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html [http://forum.world.st/Changeset-Eliminating-global-state-from-Morphic-tp5121690p5123334.html] > > > 1. Object >> #currentProject would be a *System extension in Object to not be dependent on Morphic. > 2.?? "Project current world" could be replaced with "self currentProject world" (generic) or "self currentWorld" (specific to Morphic). > 3. "Project uiManager" could be replaced with "self currentProject uiManager". > 4. "Project current addDeferredUIMessage:" could be replaced with "self currentProject addDeferredUIMessage:". > > So, we wouldn't have so many class references to "Project" in the code. It kind of reminds me about some of Newspeak's design goals. :-) > > What do you think? > I do not care for "self currentProject" because it suggests that each object is responsible for knowing its currentProject. And it is not going to save any keystrokes: 'Project current' size ==> 15 'self currentProject' size ==> 19 However, the "Project current world" idiom too wordy, and it is repeated many times. An improvement for readability might be this: Project class>>world ^self current world This would clean up a couple hundred repetitions of "Project current world" so that rather than "Project current world doOneCycle" we would say "Project world doOneCycle". It is the same as you have done for Project class>>uiManager and to me it seems better for readability. $0.02, Dave From commits at source.squeak.org Wed Mar 3 14:10:17 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 14:10:17 0000 Subject: [squeak-dev] The Trunk: Collections-nice.927.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.927.mcz ==================== Summary ==================== Name: Collections-nice.927 Author: nice Time: 3 March 2021, 3:10:15.18162 pm UUID: a5b8a84d-ad99-754f-8960-88c04b17d8d3 Ancestors: Collections-nice.926 Remaster Collections-nice.869 & Collections-nice.464: opimize RunArray This should not be noticeable for Text, but as a general library, it's important for any other potential use. - Move RunArray off ArrayedCollection which serves nothing to such subclass. - Add the ability to remove: since it already has the hability to addFirst: and addLast: - Fix a few missing lastIndex cache flush, and advertise about the necessity to do it in class comment. - prefer replace: to mapValues:, as it is a more generic Collection idiom Notice that this DOES NOT import one major change of Collections-nice.869: the enumerating methods like #collect: will continue to iterate on each element, rather than only once per run, so as to preserve side effects. Thus Collections-nice.869 remains in inbox until larger acceptation occurs. =============== Diff against Collections-nice.926 =============== Item was changed: + SequenceableCollection subclass: #RunArray - ArrayedCollection subclass: #RunArray instanceVariableNames: 'runs values lastIndex lastRun lastOffset' classVariableNames: '' poolDictionaries: '' category: 'Collections-Arrayed'! + !RunArray commentStamp: 'nice 12/30/2019 00:57' prior: 0! - !RunArray commentStamp: '' prior: 0! My instances provide space-efficient storage of data which tends to be constant over long runs of the possible indices. Essentially repeated values are stored singly and then associated with a "run" length that denotes the number of consecutive occurrences of the value. My two important variables are runs An array of how many elements are in each run values An array of what the value is over those elements The variables lastIndex, lastRun and lastOffset cache the last access so that streaming through RunArrays is not an N-squared process. + Beware: methods modifying the RunArray contents should reset the lastIndex cache to nil. Many complexities of access can be bypassed by using the method RunArray withStartStopAndValueDo:! Item was changed: ----- Method: RunArray class>>newFrom: (in category 'instance creation') ----- newFrom: aCollection "Answer an instance of me containing the same elements as aCollection." | newCollection | newCollection := self new. + newCollection fillFrom: aCollection with: [:each | each]. - aCollection do: [:x | newCollection addLast: x]. ^newCollection " RunArray newFrom: {1. 2. 2. 3} {1. $a. $a. 3} as: RunArray ({1. $a. $a. 3} as: RunArray) values "! Item was added: + ----- Method: RunArray>>asBag (in category 'converting') ----- + asBag + | aBag | + aBag := Bag new: values size. + self runsAndValuesDo: [:run :value | + aBag add: value withOccurrences: run]. + ^aBag! Item was added: + ----- Method: RunArray>>asSet (in category 'converting') ----- + asSet + ^values asSet! Item was changed: + ----- Method: RunArray>>coalesce (in category 'private') ----- - ----- Method: RunArray>>coalesce (in category 'adding') ----- coalesce + "Coalesce theRuns and theValues if ever the values have adjacent equal objects" + + | lastLength lastValue mustCoalesce coalescedRuns coalescedValued runIndex | + mustCoalesce := false. + runIndex := 0. + lastLength := 0. + lastValue := Object new. + runs with: values do: [:run :value | + (lastValue = value or: [run = 0]) + ifTrue: + [mustCoalesce + ifFalse: + [coalescedRuns := (Array new: runs size) writeStream. + coalescedValued := (Array new: values size) writeStream. + coalescedRuns next: runIndex putAll: runs startingAt: 1. + coalescedValued next: runIndex putAll: values startingAt: 1. + mustCoalesce := true]. + lastLength := lastLength + run] + ifFalse: + [lastLength > 0 + ifTrue: + [mustCoalesce + ifTrue: + [coalescedRuns nextPut: lastLength. + coalescedValued nextPut: lastValue]. + runIndex := runIndex + 1]. + lastLength := run. + lastValue := value]]. + mustCoalesce + ifTrue: + [lastLength > 0 + ifTrue: + [coalescedRuns nextPut: lastLength. + coalescedValued nextPut: lastValue]. + self setRuns: coalescedRuns contents setValues: coalescedValued contents]! - "Try to combine adjacent runs" - | ind | - ind := 2. - [ind > values size] whileFalse: [ - (values at: ind-1) = (values at: ind) - ifFalse: [ind := ind + 1] - ifTrue: ["two are the same, combine them" - values := values copyReplaceFrom: ind to: ind with: #(). - runs at: ind-1 put: (runs at: ind-1) + (runs at: ind). - runs := runs copyReplaceFrom: ind to: ind with: #(). - "self error: 'needed to combine runs' "]]. - ! Item was added: + ----- Method: RunArray>>copyUpThrough: (in category 'copying') ----- + copyUpThrough: value + "Optimized" + + | newSize newValues newRuns | + newSize := values indexOf: value startingAt: 1. + newSize = 0 ifTrue: [^self copy]. + newRuns := runs copyFrom: 1 to: newSize. + newRuns at: newSize put: 1. + newValues := values copyFrom: 1 to: newSize. + ^ self class + runs: newRuns + values: newValues! Item was added: + ----- Method: RunArray>>copyUpTo: (in category 'copying') ----- + copyUpTo: anElement + "Optimized" + + | newValues | + newValues := values copyUpTo: anElement. + ^ self class + runs: (runs copyFrom: 1 to: newValues size) + values: newValues! Item was added: + ----- Method: RunArray>>copyUpToLast: (in category 'copying') ----- + copyUpToLast: value + "Optimized" + + | newSize run newRuns newValues | + newSize := values lastIndexOf: value startingAt: values size. + newSize = 0 ifTrue: [^self copy]. + run := runs at: newSize. + run > 1 + ifTrue: + [newRuns := runs copyFrom: 1 to: newSize. + newRuns at: newSize put: run - 1] + ifFalse: + [newSize := newSize - 1. + newRuns := runs copyFrom: 1 to: newSize]. + newValues := values copyFrom: 1 to: newSize. + ^ self class + runs: newRuns + values: newValues! Item was added: + ----- Method: RunArray>>do: (in category 'enumerating') ----- + do: aBlock + "This is refined for speed" + + 1 to: runs size do: [:i | + | r v | + v := values at: i. + r := runs at: i. + [( r := r - 1) >= 0] + whileTrue: [aBlock value: v]].! Item was added: + ----- Method: RunArray>>fillFrom:with: (in category 'private') ----- + fillFrom: aCollection with: aBlock + "Evaluate aBlock with each of aCollections's elements as the argument. + Collect the resulting values into self. Answer self." + + | newRuns newValues lastLength lastValue | + newRuns := (Array new: aCollection size) writeStream. + newValues := (Array new: aCollection size) writeStream. + lastLength := 0. + lastValue := Object new. + lastIndex := nil. "flush access cache" + aCollection do: [:each | + | value | + value := aBlock value: each. + lastValue = value + ifTrue: [lastLength := lastLength + 1] + ifFalse: + [lastLength > 0 + ifTrue: + [newRuns nextPut: lastLength. + newValues nextPut: lastValue]. + lastLength := 1. + lastValue := value]]. + lastLength > 0 + ifTrue: + [newRuns nextPut: lastLength. + newValues nextPut: lastValue]. + self setRuns: newRuns contents setValues: newValues contents! Item was added: + ----- Method: RunArray>>findFirst: (in category 'enumerating') ----- + findFirst: aBlock + | index | + index := 1. + self runsAndValuesDo: [ :run :value | + (aBlock value: value) ifTrue: [^index]. + index := index + run]. + ^0! Item was added: + ----- Method: RunArray>>findLast: (in category 'enumerating') ----- + findLast: aBlock + | index | + index := values size + 1. + [(index := index - 1) >= 1] whileTrue: + [(aBlock value: (values at: index)) ifTrue: [^(1 to: index) detectSum: [:i | runs at: i]]]. + ^0! Item was added: + ----- Method: RunArray>>includes: (in category 'testing') ----- + includes: anObject + "Answer whether anObject is one of the receiver's elements." + + ^values includes: anObject! Item was added: + ----- Method: RunArray>>indexOf:startingAt: (in category 'accessing') ----- + indexOf: anElement startingAt: start + "Answer the index of the first occurence of anElement after start + within the receiver. If the receiver does not contain anElement, + answer 0." + + | index | + index := 1. + self runsAndValuesDo: [ :run :value | + (index >= start and: [value = anElement]) ifTrue: [^index]. + index := index + run]. + ^0! Item was added: + ----- Method: RunArray>>indexOfAnyOf:startingAt: (in category 'accessing') ----- + indexOfAnyOf: aCollection startingAt: start + "Answer the index of the first occurence of any element included in aCollection after start within the receiver. + If the receiver does not contain anElement, answer zero, which is an invalid index." + + | index | + index := 1. + self runsAndValuesDo: [ :run :value | + (index >= start and: [aCollection includes: value]) ifTrue: [^index]. + index := index + run]. + ^0! Item was added: + ----- Method: RunArray>>isSorted (in category 'testing') ----- + isSorted + ^values isSorted! Item was added: + ----- Method: RunArray>>isSortedBy: (in category 'testing') ----- + isSortedBy: aBlock + ^values isSortedBy: aBlock! Item was added: + ----- Method: RunArray>>keysAndValuesDo: (in category 'enumerating') ----- + keysAndValuesDo: aBlock + "This is refined for speed" + + | index | + index := 0. + 1 to: runs size do: [:i | + | r v | + v := values at: i. + r := runs at: i. + [( r := r - 1) >= 0] + whileTrue: [aBlock value: (index := index + 1) value: v]].! Item was added: + ----- Method: RunArray>>lastIndexOf:startingAt: (in category 'accessing') ----- + lastIndexOf: anElement startingAt: lastIndex + "Answer the index of the last occurence of anElement within the + receiver. If the receiver does not contain anElement, answer 0." + + | lastValueIndex | + lastValueIndex := values lastIndexOf: anElement startingAt: values size. + [lastValueIndex > 0] whileTrue: + [| i index | + i := index := 0. + [index <= lastIndex and: [(i := i + 1) <= lastValueIndex]] + whileTrue: [index := index + (runs at: i)]. + index <= lastIndex ifTrue: [^index]. + index - (runs at: lastValueIndex) < lastIndex ifTrue: [^lastIndex]. + lastValueIndex := values lastIndexOf: anElement startingAt: lastValueIndex - 1]. + ^0! Item was added: + ----- Method: RunArray>>lastIndexOfAnyOf:startingAt: (in category 'accessing') ----- + lastIndexOfAnyOf: aCollection startingAt: lastIndex + "Answer the index of the last occurence of any element of aCollection + within the receiver. If the receiver does not contain any of those + elements, answer 0" + + | lastValueIndex | + lastValueIndex := values lastIndexOfAnyOf: aCollection startingAt: values size. + [lastValueIndex > 0] whileTrue: + [| i index | + i := index := 0. + [index <= lastIndex and: [(i := i + 1) <= lastValueIndex]] + whileTrue: [index := index + (runs at: i)]. + index <= lastIndex ifTrue: [^index]. + index - (runs at: lastValueIndex) < lastIndex ifTrue: [^lastIndex]. + lastValueIndex := values lastIndexOfAnyOf: aCollection startingAt: lastValueIndex - 1]. + ^0! Item was changed: + ----- Method: RunArray>>rangeOf:startingAt: (in category 'accessing') ----- - ----- Method: RunArray>>rangeOf:startingAt: (in category 'adding') ----- rangeOf: attr startingAt: startPos "Answer an interval that gives the range of attr at index position startPos. An empty interval with start value startPos is returned when the attribute attr is not present at position startPos. self size > 0 is assumed, it is the responsibility of the caller to test for emptiness of self. Note that an attribute may span several adjancent runs. " self at: startPos setRunOffsetAndValue: [:run :offset :value | ^(value includes: attr) ifFalse: [startPos to: startPos - 1] ifTrue: [ | firstRelevantPosition lastRelevantPosition idxOfCandidateRun | lastRelevantPosition := startPos - offset + (runs at: run) - 1. firstRelevantPosition := startPos - offset. idxOfCandidateRun := run + 1. [idxOfCandidateRun <= runs size and: [(values at: idxOfCandidateRun) includes: attr]] whileTrue: [lastRelevantPosition := lastRelevantPosition + (runs at: idxOfCandidateRun). idxOfCandidateRun := idxOfCandidateRun + 1]. idxOfCandidateRun := run - 1. [idxOfCandidateRun >= 1 and: [(values at: idxOfCandidateRun) includes: attr]] whileTrue: [firstRelevantPosition := firstRelevantPosition - (runs at: idxOfCandidateRun). idxOfCandidateRun := idxOfCandidateRun - 1]. firstRelevantPosition to: lastRelevantPosition] ]! Item was added: + ----- Method: RunArray>>remove:ifAbsent: (in category 'removing') ----- + remove: anObject ifAbsent: exceptionBlock + | index mustCoalesce run | + lastIndex := nil. "flush access cache" + index := values indexOf: anObject ifAbsent: [^exceptionBlock value]. + (run := runs at: index) > 1 + ifTrue: [runs at: index put: run - 1] + ifFalse: + [mustCoalesce := index > 1 and: [index < values size and: [(values at: index - 1) = (values at: index + 1)]]. + runs := runs copyWithoutIndex: index. + values := values copyWithoutIndex: index. + mustCoalesce + ifTrue: + [runs at: index - 1 put: (runs at: index - 1) + (runs at: index). + runs := runs copyWithoutIndex: index. + values := values copyWithoutIndex: index]]. + ^anObject! Item was added: + ----- Method: RunArray>>removeAll (in category 'removing') ----- + removeAll + lastIndex := nil. "flush access cache" + runs := runs copyEmpty. + values := values copyEmpty! Item was added: + ----- Method: RunArray>>replace: (in category 'enumerating') ----- + replace: aBlock + "destructively replace the values in this RunArray with the ones transformed by aBlock." + lastIndex := nil. "flush access cache" + values := values replace: aBlock. + self coalesce! Item was added: + ----- Method: RunArray>>reverseDo: (in category 'enumerating') ----- + reverseDo: aBlock + "This is refined for speed" + + | i | + i := runs size. + [i > 0] + whileTrue: + [ | r v | + v := values at: i. + r := runs at: i. + i := i - 1. + [( r := r - 1) >= 0] + whileTrue: [aBlock value: v]].! Item was added: + ----- Method: RunArray>>withIndexDo: (in category 'enumerating') ----- + withIndexDo: aBlock + "This is refined for speed" + + | index | + index := 0. + 1 to: runs size do: [:i | + | r v | + v := values at: i. + r := runs at: i. + [( r := r - 1) >= 0] + whileTrue: [aBlock value: v value: (index := index + 1)]].! Item was changed: ----- Method: SequenceableCollection>>lastIndexOf:startingAt: (in category 'accessing') ----- lastIndexOf: anElement startingAt: lastIndex "Answer the index of the last occurence of anElement within the + receiver. If the receiver does not contain anElement, answer 0." - receiver. If the receiver does not contain anElement, answer the - result of evaluating the argument, exceptionBlock." lastIndex to: 1 by: -1 do: [ :index | (self at: index) = anElement ifTrue: [ ^index ] ]. ^0! Item was changed: ----- Method: Text>>addAttribute:from:to: (in category 'emphasis') ----- addAttribute: att from: start to: stop "Set the attribute for characters in the interval start to stop." runs := runs copyReplaceFrom: start to: stop with: ((runs copyFrom: start to: stop) + replace: - mapValues: [:attributes | Text addAttribute: att toArray: attributes]) ! Item was changed: ----- Method: Text>>removeAttribute:from:to: (in category 'emphasis') ----- removeAttribute: att from: start to: stop "Remove the attribute over the interval start to stop." runs := runs copyReplaceFrom: start to: stop with: ((runs copyFrom: start to: stop) + replace: - mapValues: [:attributes | attributes copyWithout: att]) ! From commits at source.squeak.org Wed Mar 3 14:13:56 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 14:13:56 0000 Subject: [squeak-dev] The Trunk: CollectionsTests-nice.353.mcz Message-ID: Nicolas Cellier uploaded a new version of CollectionsTests to project The Trunk: http://source.squeak.org/trunk/CollectionsTests-nice.353.mcz ==================== Summary ==================== Name: CollectionsTests-nice.353 Author: nice Time: 3 March 2021, 3:13:55.90362 pm UUID: 027a743c-cd7c-f548-98a8-7879e0fe1e36 Ancestors: CollectionsTests-nice.352 More thorough tests for optimized RunArray (companion change of Collections-nice.464) Note that those added tests lazily use well known collection class results as reference. This remasters CollectionsTests-nice.331 UUID: 0cbb84b5-6678-4fd0-bdee-73bd660b7a50 which is a false ancestor (the name conflict with trunk version), and thus moved to treated. =============== Diff against CollectionsTests-nice.352 =============== Item was added: + ----- Method: RunArrayTest>>testAddRemove (in category 'tests - instance creation') ----- + testAddRemove + | reference runArray | + reference := 'aaabcddcccbba' asOrderedCollection. + runArray := reference as: RunArray. + #((#addLast: $a) (#addLast: $d) (#addFirst: $a) (#addFirst: $d) + (#remove: $b) (#remove: $d) (#remove: $a) (#removeAll)) + do: [:selectorAndArgs | + reference perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst. + runArray perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst. + self assert: (reference as: RunArray) + equals: runArray].! Item was added: + ----- Method: RunArrayTest>>testCopy (in category 'tests - instance creation') ----- + testCopy + | reference runArray | + reference := 'aaabcddcccbba'. + runArray := reference as: RunArray. + #((#copyFrom:to: 2 9) (#copyFrom:to: 3 2) (#copyEmpty) (#copyWith: $e) (#copyWith: $a) + (#copyUpTo: $d) (#copyUpToLast: $c) (#copyUpThrough: $d)) + do: [:selectorAndArgs | + self assert: ((reference perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst) as: RunArray) + equals: (runArray perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst)].! Item was added: + ----- Method: RunArrayTest>>testIndexOf (in category 'tests - instance creation') ----- + testIndexOf + | reference runArray | + reference := 'aaabcddcccbba'. + runArray := reference as: RunArray. + #((#indexOf: $d) (#lastIndexOf: $c) (#indexOf: $e) (#indexOfAnyOf: 'cd') (#lastIndexOfAnyOf: 'cd') (#lastIndexOf: $e) + (#indexOf:startingAt: $a 7) (#lastIndexOf:startingAt: $b 7) (#indexOfAnyOf:startingAt: 'cd' 6) (#lastIndexOfAnyOf:startingAt: 'cd' 7)) + do: [:selectorAndArgs | + self assert: (reference perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst) + equals: (runArray perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst)].! Item was added: + ----- Method: RunArrayTest>>testSelectAndCollect (in category 'tests - instance creation') ----- + testSelectAndCollect + | reference runArray | + reference := 'aaabaccaabb' as: Array. + runArray := reference as: RunArray. + {{#select: . #isVowel} . {#reject: . #isVowel} . + {#collect: . [:e | 'de' atWrap: e codePoint]} . {#replace: . [:e | e codePoint // 2]}} + do: [:selectorAndArgs | + self assert: ((reference perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst) as: RunArray) + equals: (runArray perform: selectorAndArgs first withArguments: selectorAndArgs allButFirst)].! From commits at source.squeak.org Wed Mar 3 14:24:56 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 14:24:56 0000 Subject: [squeak-dev] The Trunk: CollectionsTests-nice.244.mcz Message-ID: Nicolas Cellier uploaded a new version of CollectionsTests to project The Trunk: http://source.squeak.org/trunk/CollectionsTests-nice.244.mcz ==================== Summary ==================== Name: CollectionsTests-nice.244 Author: nice Time: 6 May 2015, 11:09:57.558 pm UUID: 57fdcf9f-1ab0-45ee-873b-7117f527efbc Ancestors: CollectionsTests-mt.243 Test Dictionary replace: =============== Diff against CollectionsTests-mt.243 =============== Item was added: + ----- Method: DictionaryTest>>testReplace (in category 'testing') ----- + testReplace + | dict expected | + {Dictionary. IdentityDictionary} do: [:class | + dict := class newFromPairs:{ + #first. 1. + #second. 2. + #third. 3. + #fourth. 4. + #fifth. 5. + }. + dict replace: [:each | each asWords]. + expected := class newFromPairs:{ + #first. 'one'. + #second. 'two'. + #third. 'three'. + #fourth. 'four'. + #fifth. 'five'. + }. + self assert: dict = expected].! Item was added: + ----- Method: OrderedDictionaryTest>>testReplace (in category 'tests') ----- + testReplace + | dict expected k | + dict := OrderedDictionary newFromPairs:{ + #first. 13. + #second. 12. + #third. 11. + #fourth. 15. + #fifth. 14. + }. + k := 0. + dict replace: [:each | k := k + 1]. + expected := OrderedDictionary newFromPairs:{ + #first. 1. + #second. 2. + #third. 3. + #fourth. 4. + #fifth. 5. + }. + self assert: dict = expected.! From commits at source.squeak.org Wed Mar 3 14:25:16 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 14:25:16 0000 Subject: [squeak-dev] The Trunk: Collections-nice.634.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.634.mcz ==================== Summary ==================== Name: Collections-nice.634 Author: nice Time: 6 May 2015, 11:08:55.927 pm UUID: 4d2e458d-25c3-4b58-8df0-858fd2a6e84e Ancestors: Collections-ul.633 Implement replace: in Dictionary =============== Diff against Collections-ul.633 =============== Item was added: + ----- Method: Dictionary>>replace: (in category 'enumerating') ----- + replace: aBlock + "Destructively replace the values in this Dictionary by applying aBlock, keeping the same keys. + Implementation note: subclasses not storing the key-value pairs as a list of Associations shall refine this method." + tally = 0 ifTrue: [ ^self]. + 1 to: array size do: [ :index | + (array at: index) ifNotNil: [ :element | + element value: (aBlock value: element value) ] ]! Item was added: + ----- Method: OrderedDictionary>>replace: (in category 'enumerating') ----- + replace: aBlock + "Like super, but iterate in order." + + order from: 1 to: tally do: [:each | each value: (aBlock value: each value)]! Item was added: + ----- Method: WeakKeyDictionary>>replace: (in category 'enumerating') ----- + replace: aBlock + "Like super except that aBlock shouldn't be invoked for any reclaimed (nil) key." + + tally = 0 ifTrue: [ ^self]. + 1 to: array size do: [ :index | + (array at: index) ifNotNil: [ :association | + association key ifNotNil: [ :key | "Don't let the key go away." + association value: (aBlock value: association value) ] ] ]! From commits at source.squeak.org Wed Mar 3 14:26:42 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 14:26:42 0000 Subject: [squeak-dev] The Trunk: CollectionsTests-nice.354.mcz Message-ID: Nicolas Cellier uploaded a new version of CollectionsTests to project The Trunk: http://source.squeak.org/trunk/CollectionsTests-nice.354.mcz ==================== Summary ==================== Name: CollectionsTests-nice.354 Author: nice Time: 3 March 2021, 3:26:41.90262 pm UUID: 497e2be2-d971-624c-8e34-6ef22558b53e Ancestors: CollectionsTests-nice.353, CollectionsTests-nice.244 Merge CollectionsTests-nice.244 (test Dictionary replace:) =============== Diff against CollectionsTests-nice.353 =============== Item was added: + ----- Method: DictionaryTest>>testReplace (in category 'testing') ----- + testReplace + | dict expected | + {Dictionary. IdentityDictionary} do: [:class | + dict := class newFromPairs:{ + #first. 1. + #second. 2. + #third. 3. + #fourth. 4. + #fifth. 5. + }. + dict replace: [:each | each asWords]. + expected := class newFromPairs:{ + #first. 'one'. + #second. 'two'. + #third. 'three'. + #fourth. 'four'. + #fifth. 'five'. + }. + self assert: dict = expected].! Item was added: + ----- Method: OrderedDictionaryTest>>testReplace (in category 'tests') ----- + testReplace + | dict expected k | + dict := OrderedDictionary newFromPairs:{ + #first. 13. + #second. 12. + #third. 11. + #fourth. 15. + #fifth. 14. + }. + k := 0. + dict replace: [:each | k := k + 1]. + expected := OrderedDictionary newFromPairs:{ + #first. 1. + #second. 2. + #third. 3. + #fourth. 4. + #fifth. 5. + }. + self assert: dict = expected.! From commits at source.squeak.org Wed Mar 3 14:29:08 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 14:29:08 0000 Subject: [squeak-dev] The Trunk: Collections-nice.928.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.928.mcz ==================== Summary ==================== Name: Collections-nice.928 Author: nice Time: 3 March 2021, 3:29:05.70662 pm UUID: ef9658c8-ef7e-a943-8ffc-de7546b29f2f Ancestors: Collections-nice.927, Collections-nice.634 Merge Collections-nice.634 (Implement replace: in Dictionary) =============== Diff against Collections-nice.927 =============== Item was added: + ----- Method: Dictionary>>replace: (in category 'enumerating') ----- + replace: aBlock + "Destructively replace the values in this Dictionary by applying aBlock, keeping the same keys. + Implementation note: subclasses not storing the key-value pairs as a list of Associations shall refine this method." + tally = 0 ifTrue: [ ^self]. + 1 to: array size do: [ :index | + (array at: index) ifNotNil: [ :element | + element value: (aBlock value: element value) ] ]! Item was added: + ----- Method: OrderedDictionary>>replace: (in category 'enumerating') ----- + replace: aBlock + "Like super, but iterate in order." + + order from: 1 to: tally do: [:each | each value: (aBlock value: each value)]! Item was added: + ----- Method: WeakKeyDictionary>>replace: (in category 'enumerating') ----- + replace: aBlock + "Like super except that aBlock shouldn't be invoked for any reclaimed (nil) key." + + tally = 0 ifTrue: [ ^self]. + 1 to: array size do: [ :index | + (array at: index) ifNotNil: [ :association | + association key ifNotNil: [ :key | "Don't let the key go away." + association value: (aBlock value: association value) ] ] ]! From tim at rowledge.org Wed Mar 3 17:59:17 2021 From: tim at rowledge.org (tim Rowledge) Date: Wed, 3 Mar 2021 09:59:17 -0800 Subject: [squeak-dev] What about "self currentProject"? In-Reply-To: <20210303130834.GA31385@shell.msen.com> References: <20210303130834.GA31385@shell.msen.com> Message-ID: Add my 2c to Dave's on this question. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim When you earnestly believe you can compensate for a lack of skill by doubling your efforts, there's no end to what you can't do From marcel.taeumel at hpi.de Wed Mar 3 18:01:33 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 3 Mar 2021 19:01:33 +0100 Subject: [squeak-dev] What about "self currentProject"? In-Reply-To: References: <20210303130834.GA31385@shell.msen.com> Message-ID: Thanks! :-) I like "Project world" (besides "Project uiManager") and I understand the strange connotation of "self currentProject" ... and maybe now understand why Christoph immediately thought about dynamically re-scoping the answer like "self currentWorld". Best, Marcel Am 03.03.2021 18:59:29 schrieb tim Rowledge : Add my 2c to Dave's on this question. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim When you earnestly believe you can compensate for a lack of skill by doubling your efforts, there's no end to what you can't do -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Wed Mar 3 22:06:50 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 3 Mar 2021 22:06:50 0000 Subject: [squeak-dev] The Inbox: Kernel-jar.1377.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-jar.1377.mcz ==================== Summary ==================== Name: Kernel-jar.1377 Author: jar Time: 3 March 2021, 11:06:44.192499 pm UUID: b99e562a-887b-7e4e-9c11-6818ca1acaeb Ancestors: Kernel-nice.1376 Fix inconsistent bahavior in #isTerminated and #isSuspended =============== Diff against Kernel-nice.1376 =============== Item was changed: ----- Method: Process>>isSuspended (in category 'testing') ----- isSuspended + "A process is suspended if it has non-nil suspendedContext (e.g. new or + previously suspended with the suspend primitive) and is not terminated or + waiting in a scheduler or a semaphore queue (i.e. is not runnable or blocked)." + + ^myList isNil + and: [suspendedContext notNil] + and: [self isTerminated not]! - "A process is suspended if it has been suspended with the suspend primitive. - It is distinguishable from the active process and a terminated process by - having a non-nil suspendedContext that is either not the bottom context - or has not reached its endPC." - ^nil == myList - and: [nil ~~ suspendedContext - and: [suspendedContext isBottomContext - ifTrue: [suspendedContext closure - ifNil: [suspendedContext methodClass ~~ Process - or: [suspendedContext selector ~~ #terminate]] - ifNotNil: [suspendedContext pc < suspendedContext closure endPC]] - ifFalse: [true]]]! Item was changed: ----- Method: Process>>isTerminated (in category 'testing') ----- isTerminated + "Answer if the receiver is terminated, or at least terminating, i.e. if one + of the following conditions is satisfied: + (1) the receiver is a defunct process (suspendedContext = nil or pc = nil) + (2) we catch the active process termination by adding a first temporary + in Process>>terminate called terminationStatus and having Process>> + terminate assign #terminated to it when termination is essentially complete + (3) the suspendedContext is the bottomContext and the pc is at the endPC" + + self isActiveProcess ifTrue: [^false]. - "Answer if the receiver is terminated, or at least terminating." - self isActiveProcess ifTrue: [^ false]. ^suspendedContext isNil + or: [suspendedContext isDead] + or: [suspendedContext methodClass == Process + and: [suspendedContext selector == #terminate] + and: [(suspendedContext tempAt: 1) == #terminated]] + or: [suspendedContext isBottomContext and: [suspendedContext atEnd]]! - or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess. - If so, and the pc is at the endPC, the block has already sent and returned - from value and there is nothing more to do." - suspendedContext isBottomContext - and: [suspendedContext closure - ifNil: [suspendedContext methodClass == Process - and: [suspendedContext selector == #terminate]] - ifNotNil: [suspendedContext pc >= suspendedContext closure endPC]]]! Item was changed: ----- Method: Process>>terminate (in category 'changing process state') ----- terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." + | terminationStatus ctxt unwindBlock oldList | - | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. thisContext terminateTo: nil. + terminationStatus := #terminated. self suspend. "If the process is resumed this will provoke a cannotReturn: error. Would self debug: thisContext title: 'Resuming a terminated process' be better?" ^self]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: [self debug: ctxt title: 'Unwind error during termination']. "Set the context to its endPC for the benefit of isTerminated." ctxt pc: ctxt endPC]! From m at jaromir.net Wed Mar 3 22:10:45 2021 From: m at jaromir.net (Jaromir Matas) Date: Wed, 3 Mar 2021 16:10:45 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1377.mcz In-Reply-To: References: Message-ID: <1614809445996-0.post@n4.nabble.com> Fix inconsistent bahavior in #isTerminated and #isSuspended Following up on a discussion with Eliot ( http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html ) I'm proposing changes to #isTerminated, #isSuspended and Eliot's hack to #terminate to remove inconsistency in reporting the termination status in some rare cases. A suggestion: When a process is terminated and later resumed it raises a cannotReturn: error. Is raising an error/debugger desirable? Looping the resumed process back to terminate would do no harm and raise no error... terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | terminationStatus ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. thisContext terminateTo: nil. terminationStatus := #terminated. self suspend. >>> thisContext restart]. "add this and remove ^self below" "If the process is resumed this will provoke a cannotReturn: error. Would self debug: thisContext title: 'Resuming a terminated process' be better?" ^self]. "..." And finally: Is there a reason why processes created directly via Process forContext:priority: are not subject to tests? Like e.g.: "These processes should be terminated, not suspended." self deny: (Process forContext: [Processor activeProcess suspend] priority: Processor activePriority + 1) resume isSuspended. self assert: (Process forContext: [Processor activeProcess suspend] priority: Processor activePriority + 1) resume isTerminated. If not, I could add some... regards, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From lewis at mail.msen.com Wed Mar 3 22:15:31 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Wed, 3 Mar 2021 17:15:31 -0500 Subject: [squeak-dev] The Trunk: CollectionsTests-dtl.350.mcz In-Reply-To: References: <1614686391666-0.post@n4.nabble.com> Message-ID: <20210303221531.GA22155@shell.msen.com> On Tue, Mar 02, 2021 at 09:08:29AM -0800, Eliot Miranda wrote: > > > > On Mar 2, 2021, at 3:59 AM, Christoph Thiede wrote: > > > > ???Hi Dave, > > > > could there be something wrong with the ancestry of this version? The > > notification email does not contain any visible diff and when updating my > > image today, I got an MCEmptyDiffyVersion warning. > > +1 > Yes, it looks like I made a mistake here. My intention was to bypass CollectionsTests-jar.349 entirely by letting CollectionsTests-ul.348 be the sole ancestor of CollectionsTests-dtl.350 with no changes between 348 and 350. This was the wrong thing to do because many people already had 349 loaded in their image. I do not think that I can fix the 350 version without causing additional problems for the update stream. It should not cause a problem for the update stream in general, but for everyone who had already updated to 349, a manual update of CollectionTests is probably necessary. I apologize for the error :-( Dave From asqueaker at gmail.com Thu Mar 4 03:14:40 2021 From: asqueaker at gmail.com (Chris Muller) Date: Wed, 3 Mar 2021 21:14:40 -0600 Subject: [squeak-dev] The Trunk: CollectionsTests-dtl.350.mcz In-Reply-To: <20210303221531.GA22155@shell.msen.com> References: <1614686391666-0.post@n4.nabble.com> <20210303221531.GA22155@shell.msen.com> Message-ID: > > > On Mar 2, 2021, at 3:59 AM, Christoph Thiede < > christoph.thiede at student.hpi.uni-potsdam.de> wrote: > > > > > > ???Hi Dave, > > > > > > could there be something wrong with the ancestry of this version? The > > > notification email does not contain any visible diff and when updating > my > > > image today, I got an MCEmptyDiffyVersion warning. > Dave's comment explicitly acknowledged the omission of 349. I'm curious why you would assume something's wrong. It's one of several Warnings, but it's not an Error. > Yes, it looks like I made a mistake here. My intention was to bypass > CollectionsTests-jar.349 entirely by letting CollectionsTests-ul.348 > be the sole ancestor of CollectionsTests-dtl.350 with no changes between > 348 and 350. This was the wrong thing to do because many people already > had 349 loaded in their image. > That doesn't make it wrong in the least. You had good reason to exclude it from the ancestry. I personally would've simply deleted 349 from the repository and not even made 350. The coherence and correctness of the permanent ancestry far outweighs the temporary in-RAM state of a developers' image, which isn't confusing if one pays the ancestry the attention it deserves. > I do not think that I can fix the 350 version without causing additional > problems for the update stream. It should not cause a problem for the > update stream in general, but for everyone who had already updated to > 349, a manual update of CollectionTests is probably necessary. > > I apologize for the error :-( I put that Warning message in years ago for no more than debugging an issue at that time. It should be removed. Not only is there no need to apologize, but thanks for doing the right thing. - Chris -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 4 08:04:21 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 08:04:21 0000 Subject: [squeak-dev] The Trunk: MorphicTests-mt.73.mcz Message-ID: Marcel Taeumel uploaded a new version of MorphicTests to project The Trunk: http://source.squeak.org/trunk/MorphicTests-mt.73.mcz ==================== Summary ==================== Name: MorphicTests-mt.73 Author: mt Time: 4 March 2021, 9:04:20.359869 am UUID: 51b5fae1-e96f-9045-9bc9-2a7561c0cacb Ancestors: MorphicTests-mt.72 Adds test for owner-changed handler, which is a simple layout hook that does not require a layout policy. Fixes a name in a grid-layout test. =============== Diff against MorphicTests-mt.72 =============== Item was added: + ----- Method: GridLayoutTest>>test05AdhereToEdge (in category 'tests') ----- + test05AdhereToEdge + "The grid should be ignored for morphs that snap to their owner's edges." + + | m | + m := Morph new color: Color random; extent: 10 at 10; yourself. + container addMorph: m. + + "1) Manual adhere-to-edge will not work." + m position: 0@(100 - 10). + container fullBounds. + self assert: 0 at 100 equals: m position. + + "2) Use adhere-to-edge property." + m setToAdhereToEdge: #bottom. + container fullBounds. + self assert: 0@(100 - 10) equals: m position.! Item was removed: - ----- Method: GridLayoutTest>>test05SnapToEdge (in category 'tests') ----- - test05SnapToEdge - "The grid should be ignored for morphs that snap to their owner's edges." - - | m | - m := Morph new color: Color random; extent: 10 at 10; yourself. - container addMorph: m. - - "1) Manual snap-to-edge will not work." - m position: 0@(100 - 10). - container fullBounds. - self assert: 0 at 100 equals: m position. - - "2) Use snap-to-edge property." - m setToAdhereToEdge: #bottom. - container fullBounds. - self assert: 0@(100 - 10) equals: m position.! Item was added: + ----- Method: MorphLayoutTest>>makeYellow: (in category 'helper') ----- + makeYellow: aMorph + + aMorph color: Color yellow.! Item was added: + ----- Method: MorphLayoutTest>>testOwnerChangedHandler (in category 'tests') ----- + testOwnerChangedHandler + + | m1 m2 | + m1 := Morph new extent: 100 at 100; yourself. + m2 := Morph new extent: 10 at 10; yourself. + + m1 addMorph: m2. + self ensureLayout: m1. + self assert: 10 at 10 equals: m2 extent. + + m2 ownerChangedHandler: [:m | m extent: m owner extent]. + self ensureLayout: m1. + self assert: 100 at 100 equals: m2 extent. + + m2 color: Color red. + m2 ownerChangedHandler: (MessageSend receiver: self selector: #makeYellow:). + self assert: Color red equals: m2 color. + self ensureLayout: m1. + self assert: Color yellow equals: m2 color. + + m2 ownerChangedHandler: #delete. + self assert: m1 hasSubmorphs. + self ensureLayout: m1. + self deny: m1 hasSubmorphs.! From m at jaromir.net Thu Mar 4 09:03:13 2021 From: m at jaromir.net (Jaromir Matas) Date: Thu, 4 Mar 2021 03:03:13 -0600 (CST) Subject: [squeak-dev] Simulation guard crashes the image Message-ID: <1614848593348-0.post@n4.nabble.com> Hi, why the simulation guard in BlockClosure >> newProcess? It crashes the image when debugging e.g. [] fork. You hit Into -> Into -> the the error window pops up, you cancel it (or Abandon...) and hit Into again and the image is done :| In case there's no reason to keep the simulation guard why not just remove it? Thanks, Squeak6.0alpha-20243-64bit-202003021730-Windows ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 4 11:08:04 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 4 Mar 2021 11:08:04 +0000 Subject: [squeak-dev] Simulation guard crashes the image In-Reply-To: <1614848593348-0.post@n4.nabble.com> References: <1614848593348-0.post@n4.nabble.com> Message-ID: <7906b282ca044bf3b907ac9c9ee4c2da@student.hpi.uni-potsdam.de> Hi Jaromir, thanks for your report. There are two problems here: 1. The usage of primitive 19 in #newProcess, which I'm glad not to be the only person to find it questionary. I already mentioned this here: http://forum.world.st/Just-another-debugger-bug-primitive-19-td5109411.html IMO the primitive does not make sense in this place, rather we should raise the simulation guard when primitiveSuspend or primitiveResume is invoked via simulation. Still, it is not necessarily a bad thing to let these things happen during simulation - that's why I would prefer to show some confirmation dialog instead of a warning. This is already on my to-do list and a solution for the second aspect should arrive in the Trunk during the next weeks. :-) 2. Debugger chains crashing your image, which has already been discussed in great detail in http://forum.world.st/I-broke-the-debugger-td5110752.html#a5124736. I found the cause of the issue and have provided two possible solutions in this thread. Marcel and I are currently discussing the last details of the patch, but it should be complete soon and will arrive in the Trunk, probably together with the extended simulation guard as noted above! If you find further interesting bugs, please let us know them all. :D Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Donnerstag, 4. März 2021 10:03:13 An: squeak-dev at lists.squeakfoundation.org Betreff: [squeak-dev] Simulation guard crashes the image Hi, why the simulation guard in BlockClosure >> newProcess? It crashes the image when debugging e.g. [] fork. You hit Into -> Into -> the the error window pops up, you cancel it (or Abandon...) and hit Into again and the image is done :| In case there's no reason to keep the simulation guard why not just remove it? Thanks, Squeak6.0alpha-20243-64bit-202003021730-Windows ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 4 12:35:29 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 12:35:29 0000 Subject: [squeak-dev] The Trunk: System-mt.1220.mcz Message-ID: Marcel Taeumel uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-mt.1220.mcz ==================== Summary ==================== Name: System-mt.1220 Author: mt Time: 4 March 2021, 1:35:25.601178 pm UUID: d5324489-3128-a944-a52b-faf8d4c8ef23 Ancestors: System-mt.1219 Squeak was migrated from travis-ci.org to travis-ci.com. The former will be shutting down soon. =============== Diff against System-mt.1219 =============== Item was changed: ----- Method: SystemVersion>>ciStatusBadgeUrl (in category 'continuous integration') ----- ciStatusBadgeUrl | branch | branch := 'squeak-{1}{2}{3}' format: { self isRelease ifTrue: [self majorVersionNumber] ifFalse: ['']. self isRelease ifTrue: ['.'] ifFalse: ['trunk']. self isRelease ifTrue: [self minorVersionNumber] ifFalse: [''] }. + ^ 'https://api.travis-ci.com/squeak-smalltalk/squeak-app.png?branch=', branch! - ^ 'https://api.travis-ci.org/squeak-smalltalk/squeak-app.png?branch=', branch! Item was changed: ----- Method: SystemVersion>>ciStatusPageUrl (in category 'continuous integration') ----- ciStatusPageUrl "In a release image, let the user see the overview of branches to choose from. I am not aware of a permanent link for a specific branch. In a trunk image, just let Travis report the state of the main branch, which is usually for trunk builds." + ^ 'http://travis-ci.com/squeak-smalltalk/squeak-app{1}' format: { - ^ 'http://travis-ci.org/squeak-smalltalk/squeak-app{1}' format: { self isRelease ifFalse: [''] ifTrue: ['/branches'] }! From commits at source.squeak.org Thu Mar 4 14:25:38 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 14:25:38 0000 Subject: [squeak-dev] The Trunk: ToolBuilder-Kernel-mt.139.mcz Message-ID: Marcel Taeumel uploaded a new version of ToolBuilder-Kernel to project The Trunk: http://source.squeak.org/trunk/ToolBuilder-Kernel-mt.139.mcz ==================== Summary ==================== Name: ToolBuilder-Kernel-mt.139 Author: mt Time: 4 March 2021, 3:25:37.860661 pm UUID: a8f8f119-901d-0045-b619-a7d25e0530ef Ancestors: ToolBuilder-Kernel-mt.138 Makes the transfer type for drag-and-drop configurable. =============== Diff against ToolBuilder-Kernel-mt.138 =============== Item was changed: PluggableWidgetSpec subclass: #PluggableListSpec + instanceVariableNames: 'list getIndex setIndex getSelected setSelected menu keyPress autoDeselect dragItem dragType dropItem dropAccept doubleClick listSize listItem keystrokePreview icon vScrollBarPolicy hScrollBarPolicy dragStarted helpItem filterableList clearFilterAutomatically itemAlignment itemPadding' - instanceVariableNames: 'list getIndex setIndex getSelected setSelected menu keyPress autoDeselect dragItem dropItem dropAccept doubleClick listSize listItem keystrokePreview icon vScrollBarPolicy hScrollBarPolicy dragStarted helpItem filterableList clearFilterAutomatically itemAlignment itemPadding' classVariableNames: '' poolDictionaries: '' category: 'ToolBuilder-Kernel'! !PluggableListSpec commentStamp: 'ar 7/15/2005 11:54' prior: 0! A single selection list element. Instance variables: list The selector to retrieve the list elements. getIndex The selector to retrieve the list selection index. setIndex The selector to set the list selection index. getSelected The selector to retrieve the list selection. setSelected The selector to set the list selection. menu The selector to offer (to retrieve?) the context menu. keyPress The selector to invoke for handling keyboard shortcuts. autoDeselect Whether the list should allow automatic deselection or not. dragItem Selector to initiate a drag action on an item dropItem Selector to initiate a drop action of an item dropAccept Selector to determine whether a drop would be accepted! Item was added: + ----- Method: PluggableListSpec>>dragType (in category 'accessing - drag and drop') ----- + dragType + "Answer the selector to determine the type that can be used configure the drop." + + ^ dragType! Item was added: + ----- Method: PluggableListSpec>>dragType: (in category 'accessing - drag and drop') ----- + dragType: aSymbol + "Answer the selector to determine the type that can be used configure the drop." + + dragType := aSymbol.! From commits at source.squeak.org Thu Mar 4 14:26:13 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 14:26:13 0000 Subject: [squeak-dev] The Trunk: ToolBuilder-Morphic-mt.274.mcz Message-ID: Marcel Taeumel uploaded a new version of ToolBuilder-Morphic to project The Trunk: http://source.squeak.org/trunk/ToolBuilder-Morphic-mt.274.mcz ==================== Summary ==================== Name: ToolBuilder-Morphic-mt.274 Author: mt Time: 4 March 2021, 3:26:12.332661 pm UUID: 7491b055-3449-2a40-925a-75174efc5215 Ancestors: ToolBuilder-Morphic-mt.273 Complements ToolBuilder-Kernel-mt.139 =============== Diff against ToolBuilder-Morphic-mt.273 =============== Item was changed: ----- Method: MorphicToolBuilder>>buildPluggableList: (in category 'widgets required') ----- buildPluggableList: aSpec | widget listClass getIndex setIndex | aSpec getSelected ifNil:[ listClass := self listClass. getIndex := aSpec getIndex. setIndex := aSpec setIndex. ] ifNotNil:[ listClass := self listByItemClass. getIndex := aSpec getSelected. setIndex := aSpec setSelected. ]. widget := listClass on: aSpec model list: aSpec list selected: getIndex changeSelected: setIndex menu: aSpec menu keystroke: aSpec keyPress. self register: widget id: aSpec name. widget dragItemSelector: aSpec dragItem; dropItemSelector: aSpec dropItem; wantsDropSelector: aSpec dropAccept; + dragStartedSelector: aSpec dragStarted; + dragTypeSelector: aSpec dragType. - dragStartedSelector: aSpec dragStarted. self setListPropertiesFor: widget spec: aSpec. ^widget! From commits at source.squeak.org Thu Mar 4 14:33:51 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 14:33:51 0000 Subject: [squeak-dev] The Trunk: Tools-mt.1028.mcz Message-ID: Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1028.mcz ==================== Summary ==================== Name: Tools-mt.1028 Author: mt Time: 4 March 2021, 3:33:48.778661 pm UUID: ac105d50-b9ae-9f48-9233-3c4e5bdd741f Ancestors: Tools-mt.1027 Makes CodeHolder useful by itself. It can easily be used to show and edit a single compiled method. Compilation logic extracted from Browser. =============== Diff against Tools-mt.1027 =============== Item was changed: + ----- Method: CodeHolder>>aboutToStyle: (in category 'code pane') ----- - ----- Method: CodeHolder>>aboutToStyle: (in category 'contents') ----- aboutToStyle: aStyler - "This is a notification that aStyler is about to re-style its text. - The default is to answer false to veto the styling" + currentCompiledMethod ifNil: [^ false]. + aStyler classOrMetaClass: self selectedClassOrMetaClass. + ^ true! - ^false! Item was added: + ----- Method: CodeHolder>>compileMessage:notifying: (in category 'code pane') ----- + compileMessage: aString notifying: aController + "Compile the code that was accepted by the user, placing the compiled method into an appropriate message category. Return true if the compilation succeeded, else false." + + | selectedMessageName selector category selectedClassOrMetaClass | + selectedMessageName := self selectedMessageName. + selectedClassOrMetaClass := self selectedClassOrMetaClass. + contents := nil. + selector := (selectedClassOrMetaClass newParser parseSelector: aString). + (self metaClassIndicated + and: [(selectedClassOrMetaClass includesSelector: selector) not + and: [Metaclass isScarySelector: selector]]) + ifTrue: ["A frist-time definition overlaps the protocol of Metaclasses" + (self confirm: ((selector , ' is used in the existing class system. + Overriding it could cause serious problems. + Is this really what you want to do?') asText makeBoldFrom: 1 to: selector size)) + ifFalse: [^nil]]. + category := self selectedMessageCategoryName. + selector := selectedClassOrMetaClass + compile: aString + classified: category + notifying: aController. + selector == nil ifTrue: [^ nil]. + contents := aString copy. + currentCompiledMethod := selectedClassOrMetaClass compiledMethodAt: selector. + ^ true! Item was added: + ----- Method: CodeHolder>>contents:notifying: (in category 'accessing') ----- + contents: input notifying: aController + "The retrieved information has changed and its source must now be updated. Answer the result of updating the source." + + self changed: #annotation. + + ^ self okayToAccept + ifFalse: [false] + ifTrue: [self compileMessage: input asText notifying: aController].! Item was added: + ----- Method: CodeHolder>>defaultBrowserTitle (in category 'initialize-release') ----- + defaultBrowserTitle + + ^ 'Source Code'! Item was added: + ----- Method: CodeHolder>>labelString (in category 'initialize-release') ----- + labelString + + | label | + label := self defaultBrowserTitle. + currentCompiledMethod ifNotNil: [ + label := label, (': {1} >> #{2} ({3})' format: { + self selectedClassOrMetaClass name. + self selectedMessageName. + self selectedMessageCategoryName })]. + ^ label! Item was added: + ----- Method: CodeHolder>>metaClassIndicated (in category 'accessing') ----- + metaClassIndicated + + ^ self selectedClassOrMetaClass isMeta! Item was added: + ----- Method: CodeHolder>>selectedClass (in category 'accessing') ----- + selectedClass + + ^ self selectedClassOrMetaClass ifNotNil: [:cls | cls theNonMetaClass]! Item was added: + ----- Method: CodeHolder>>selectedClassOrMetaClass (in category 'accessing') ----- + selectedClassOrMetaClass + + ^ currentCompiledMethod ifNotNil: [:method | method methodClass]! Item was added: + ----- Method: CodeHolder>>selectedMessageName (in category 'accessing') ----- + selectedMessageName + + ^ currentCompiledMethod + ifNil: [super selectedMessageName] + ifNotNil: [:method | method selector]! Item was added: + ----- Method: CodeHolder>>setClass:selector: (in category 'initialize-release') ----- + setClass: aBehavior selector: aSymbol + + contents := nil. + currentCompiledMethod := aBehavior compiledMethodAt: aSymbol. + self changed: #relabel. + self contentsChanged. + self decorateButtons.! From commits at source.squeak.org Thu Mar 4 14:36:26 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 14:36:26 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1733.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1733.mcz ==================== Summary ==================== Name: Morphic-mt.1733 Author: mt Time: 4 March 2021, 3:36:21.510661 pm UUID: 6c985504-3f57-4349-9f09-1476a647e3a3 Ancestors: Morphic-mt.1732 Rudimentary support for dropping source-code artifacts into the world. Just attach #sourceCode as #dragTransferType during a drag operation to trigger the code path. =============== Diff against Morphic-mt.1732 =============== Item was changed: ----- Method: PasteUpMorph>>acceptDroppingMorph:event: (in category 'dropping/grabbing') ----- acceptDroppingMorph: dropped event: evt "The supplied morph, known to be acceptable to the receiver, is now to be assimilated; the precipitating event is supplied" | aMorph | + (self isWorldMorph and: [dropped isTransferMorph]) ifTrue: [ + dropped dragTransferType = #filesAndDirectories + ifTrue: [^ self dropFiles: dropped passenger event: evt]. + dropped dragTransferType = #sourceCode + ifTrue: [^ self dropSourceCode: dropped passenger event: evt]]. - (self isWorldMorph and: - [dropped isTransferMorph and: - [dropped dragTransferType = #filesAndDirectories]]) ifTrue: - [^ self dropFiles: dropped passenger event: evt]. aMorph := self morphToDropFrom: dropped. self isWorldMorph ifFalse: [super acceptDroppingMorph: aMorph event: evt] ifTrue: ["Add the given morph to this world and start stepping it if it wants to be." aMorph isInWorld ifFalse: [aMorph position: evt position]. self addMorphFront: aMorph. (aMorph fullBounds intersects: self viewBox) ifFalse: [Beeper beep. aMorph position: self bounds center]]. aMorph submorphsDo: [:m | (m isKindOf: HaloMorph) ifTrue: [m delete]]. aMorph allMorphsDo: "Establish any penDown morphs in new world" [:m | | tfm mm | m player ifNotNil: [m player getPenDown ifTrue: [((mm := m player costume) notNil and: [(tfm := mm owner transformFrom: self) notNil]) ifTrue: [self noteNewLocation: (tfm localPointToGlobal: mm referencePosition) forPlayer: m player]]]]. self isPartsBin ifTrue: [aMorph isPartsDonor: true. aMorph stopSteppingSelfAndSubmorphs. aMorph suspendEventHandler] ifFalse: [self world startSteppingSubmorphsOf: aMorph]. " self presenter morph: aMorph droppedIntoPasteUpMorph: self." self showingListView ifTrue: [self sortSubmorphsBy: (self valueOfProperty: #sortOrder). self currentWorld abandonAllHalos]. self bringTopmostsToFront.! Item was added: + ----- Method: PasteUpMorph>>dropSourceCode:event: (in category 'event handling') ----- + dropSourceCode: anObject event: evt + + anObject isCompiledMethod + ifTrue: [ + | tool window | + tool := CodeHolder new + setClass: anObject methodClass + selector: anObject selector. + window := ToolBuilder open: tool. + window center: evt position. + window bounds: (window bounds translatedToBeWithin: self bounds)]. + + anObject isString + ifTrue: [anObject edit].! Item was changed: ----- Method: PasteUpMorph>>wantsDroppedTransferMorph: (in category 'dropping/grabbing') ----- wantsDroppedTransferMorph: transferMorph ^ self hasTransferMorphConverter + or: [transferMorph dragTransferType = #filesAndDirectories] + or: [transferMorph dragTransferType = #sourceCode]! - or: [transferMorph dragTransferType = #filesAndDirectories]! From commits at source.squeak.org Thu Mar 4 14:38:38 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 14:38:38 0000 Subject: [squeak-dev] The Trunk: Tools-mt.1029.mcz Message-ID: Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1029.mcz ==================== Summary ==================== Name: Tools-mt.1029 Author: mt Time: 4 March 2021, 3:38:36.350661 pm UUID: bef0c471-6ff1-774d-860e-8958e1aa508b Ancestors: Tools-mt.1028 Enable source-code dragging through a browser's message list to be dropped into the world to open a compact code editor. Complements Tools-mt.1028, ToolBuilder-Kernel-mt.139, ToolBuilder-Morphic-mt.274, and Morphic-mt.1733. =============== Diff against Tools-mt.1028 =============== Item was changed: ----- Method: Browser>>buildMessageListWith: (in category 'toolbuilder') ----- buildMessageListWith: builder | listSpec | listSpec := builder pluggableListSpec new. listSpec model: self; list: #messageList; getIndex: #messageListIndex; setIndex: #messageListIndex:; icon: #messageIconAt:; helpItem: #messageHelpAt:; menu: #messageListMenu:shifted:; keyPress: #messageListKey:from:. + SystemBrowser browseWithDragNDrop ifTrue: [ + listSpec + dragItem: #dragFromMessageList:; + dragType: #dragTypeForMessageListAt:]. - SystemBrowser browseWithDragNDrop - ifTrue:[listSpec dragItem: #dragFromMessageList:]. ^listSpec ! Item was added: + ----- Method: Browser>>dragTypeForMessageListAt: (in category 'drag and drop') ----- + dragTypeForMessageListAt: index + + ^ #sourceCode! From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 4 14:42:52 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 4 Mar 2021 14:42:52 +0000 Subject: [squeak-dev] smalltalkCI is broken for Trunk Message-ID: FYIO: https://github.com/hpi-swa/smalltalkCI/issues/502 (If you have any ideas on how to solve this, please let's not split up the discussion onto the mailing list, we would all loose track ...) -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Thu Mar 4 14:46:49 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 4 Mar 2021 15:46:49 +0100 Subject: [squeak-dev] The Trunk: Tools-mt.1029.mcz In-Reply-To: References: Message-ID: Here is an example: Am 04.03.2021 15:38:47 schrieb commits at source.squeak.org : Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1029.mcz ==================== Summary ==================== Name: Tools-mt.1029 Author: mt Time: 4 March 2021, 3:38:36.350661 pm UUID: bef0c471-6ff1-774d-860e-8958e1aa508b Ancestors: Tools-mt.1028 Enable source-code dragging through a browser's message list to be dropped into the world to open a compact code editor. Complements Tools-mt.1028, ToolBuilder-Kernel-mt.139, ToolBuilder-Morphic-mt.274, and Morphic-mt.1733. =============== Diff against Tools-mt.1028 =============== Item was changed: ----- Method: Browser>>buildMessageListWith: (in category 'toolbuilder') ----- buildMessageListWith: builder | listSpec | listSpec := builder pluggableListSpec new. listSpec model: self; list: #messageList; getIndex: #messageListIndex; setIndex: #messageListIndex:; icon: #messageIconAt:; helpItem: #messageHelpAt:; menu: #messageListMenu:shifted:; keyPress: #messageListKey:from:. + SystemBrowser browseWithDragNDrop ifTrue: [ + listSpec + dragItem: #dragFromMessageList:; + dragType: #dragTypeForMessageListAt:]. - SystemBrowser browseWithDragNDrop - ifTrue:[listSpec dragItem: #dragFromMessageList:]. ^listSpec ! Item was added: + ----- Method: Browser>>dragTypeForMessageListAt: (in category 'drag and drop') ----- + dragTypeForMessageListAt: index + + ^ #sourceCode! -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 412422 bytes Desc: not available URL: From marcel.taeumel at hpi.de Thu Mar 4 15:08:39 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 4 Mar 2021 16:08:39 +0100 Subject: [squeak-dev] smalltalkCI is broken for Trunk In-Reply-To: References: Message-ID: I found the issue. "update-nice.469.mcm" got corrupted. It points to completely wrong versions, that is, versions that are way too young compared to the time when 469 was created. Looking at 470 and 468, you will see the issue. Yet, I do not know how to get a backup for 469 into the update stream. Any ideas? For example, 469 states that it needs "Collections-jar.924" but it should be something around "Collections-nice.893". How could this happen? It it really possible to simple overwrite an existing version from the image? Woah .... :-) Best, Marcel Am 04.03.2021 15:43:01 schrieb Thiede, Christoph : FYIO: https://github.com/hpi-swa/smalltalkCI/issues/502 [https://github.com/hpi-swa/smalltalkCI/issues/502] (If you have any ideas on how to solve this, please let's not split up the discussion onto the mailing list, we would all loose track ...) -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Thu Mar 4 15:20:59 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 4 Mar 2021 16:20:59 +0100 Subject: [squeak-dev] smalltalkCI is broken for Trunk In-Reply-To: References: Message-ID: I made an educated guess and restored "update-nice.469.mcm" to this: Squeak-Version-mt.5252 60Deprecated-mt.75 Balloon-dtl.32 WebClient-HTTP-cmm.6 Network-dtl.240 Compression-dtl.55 Graphics-mt.430 Multilingual-nice.252 PackageInfo-Base-mt.72 Compiler-nice.432 Collections-nice.892 Environments-dtl.77 Chronology-Core-nice.52 Kernel-nice.1326 System-mt.1155 Monticello-eem.717 Files-pre.183 Installer-Core-mt.439 CollectionsTests-nice.338 GraphicsTests-eem.54 Chronology-Tests-mt.23 KernelTests-mt.380 SqueakSSL-Core-topa.33 SqueakSSL-SMTP-ar.1 SqueakSSL-Tests-pre.24 GetText-mt.48 Sound-dtl.68 ToolBuilder-Kernel-mt.138 ToolBuilder-Tests-mt.5 Morphic-nice.1658 MorphicTests-mt.61 MorphicExtras-mt.274 MorphicExtrasTests-mt.6 MonticelloConfigurations-dtl.161 MultilingualTests-pre.37 NetworkTests-pre.58 Nebraska-mt.56 EToys-mt.391 PreferenceBrowser-mt.103 Protocols-mt.73 SMBase-nice.143 SMLoader-cmm.93 ST80-nice.254 ST80Tests-fn.6 ST80Tools-mt.12 SUnit-mt.121 SUnitGUI-mt.79 SUnitTools-tcj.4 Services-Base-jr.68 SystemChangeNotification-Tests-ul.28 Tests-dtl.432 ToolBuilder-MVC-mt.59 ToolBuilder-Morphic-mt.258 ToolBuilder-SUnit-mt.20 Tools-jr.966 ToolsTests-mt.95 MonticelloForTraits-fbs.1 Traits-pre.312 TraitsTests-mt.25 TrueType-mt.53 VersionNumber-cmm.4 XML-Parser-tpr.45 XML-Explorer-topa.1 ReleaseBuilder-mt.209 ShoutCore-mt.77 ShoutTests-ct.32 VersionNumberTests-fbs.4 HelpSystem-Core-mt.119 HelpSystem-Tests-pre.21 Help-Squeak-Project-nice.80 Help-Squeak-TerseGuide-mt.14 Help-Squeak-SWiki-mt.2 Help-Squeak-CorePackages-tpr.5 SystemReporter-mt.42 BalloonTests-egp.2 CommandLine-mt.16 UpdateStream-mt.15 WebClient-Core-tobe.121 WebClient-Tests-nice.59 WebClient-Help-kfr.11 Regex-Core-ul.57 Regex-Tests-Core-nice.10 Am 04.03.2021 16:08:39 schrieb Marcel Taeumel : I found the issue. "update-nice.469.mcm" got corrupted. It points to completely wrong versions, that is, versions that are way too young compared to the time when 469 was created. Looking at 470 and 468, you will see the issue. Yet, I do not know how to get a backup for 469 into the update stream. Any ideas? For example, 469 states that it needs "Collections-jar.924" but it should be something around "Collections-nice.893". How could this happen? It it really possible to simple overwrite an existing version from the image? Woah .... :-) Best, Marcel Am 04.03.2021 15:43:01 schrieb Thiede, Christoph : FYIO: https://github.com/hpi-swa/smalltalkCI/issues/502 [https://github.com/hpi-swa/smalltalkCI/issues/502] (If you have any ideas on how to solve this, please let's not split up the discussion onto the mailing list, we would all loose track ...) -------------- next part -------------- An HTML attachment was scrubbed... URL: From Marcel.Taeumel at hpi.de Thu Mar 4 15:30:14 2021 From: Marcel.Taeumel at hpi.de (marcel.taeumel) Date: Thu, 4 Mar 2021 09:30:14 -0600 (CST) Subject: [squeak-dev] Morphic team, nice improvement during installer runs. The progress bar stays in top right... In-Reply-To: <177642fc86e.114e3871628639.4614723699233167822@zoho.com> References: <177642fc86e.114e3871628639.4614723699233167822@zoho.com> Message-ID: <1614871814882-0.post@n4.nabble.com> Hi, there. What do you mean "top right"? The labels should be "top left" aligned with their bars unless they are bigger than the bars. In that case, they get centered. Not sure why this is what we want. For nested bars, UI still seems to jiggle between topLeft and center sometimes. Best, Marcel -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Thu Mar 4 15:47:22 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 15:47:22 0000 Subject: [squeak-dev] The Trunk: Monticello-mt.736.mcz Message-ID: Marcel Taeumel uploaded a new version of Monticello to project The Trunk: http://source.squeak.org/trunk/Monticello-mt.736.mcz ==================== Summary ==================== Name: Monticello-mt.736 Author: mt Time: 4 March 2021, 4:47:21.662431 pm UUID: 79f9cc15-fc98-ad48-9907-49abd9a3808e Ancestors: Monticello-mt.735 Fixes typo. =============== Diff against Monticello-mt.735 =============== Item was changed: ----- Method: MCRepositoryInspector>>save (in category 'actions') ----- save self pickRepository ifNotNil: [:repository | (self repository = MCRepository inbox and: [repository = MCRepository trunk or: [repository = MCRepository treated]]) ifTrue: + [self notify: 'Versions from the inbox should only be moved, not copied. Instead, use the web interface via source.squeak.org to manage inbox contributions.\\Do you want to proceed anyway?' translated withCRs]. - [self notify: 'Versions from the inbox should only be moved, not copied. Instead, use the web interface via source.squeak.org to manage inbox constributions.\\Do you want to proceed anyway?' translated withCRs]. repository storeVersion: self version]! From commits at source.squeak.org Thu Mar 4 15:48:09 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 15:48:09 0000 Subject: [squeak-dev] The Trunk: MonticelloConfigurations-mt.165.mcz Message-ID: Marcel Taeumel uploaded a new version of MonticelloConfigurations to project The Trunk: http://source.squeak.org/trunk/MonticelloConfigurations-mt.165.mcz ==================== Summary ==================== Name: MonticelloConfigurations-mt.165 Author: mt Time: 4 March 2021, 4:48:08.507431 pm UUID: bc7f26e0-4549-cc43-9e87-b1e9dd0c96d0 Ancestors: MonticelloConfigurations-mt.164 Adds a safe guard to not overwrite existing configurations in the update map by accident. =============== Diff against MonticelloConfigurations-mt.164 =============== Item was changed: ----- Method: MCConfigurationBrowser>>completeStoreAction (in category 'actions') ----- completeStoreAction "The store method will arrange for this to be called after the user has entered a comment for the configuration version being stored." self activeEditWindow: nil. "Close the editor window" self pickRepository ifNotNil: [:repo | configuration authorInitials: Utilities authorInitials. configuration timeStamp: (DateAndTime fromSeconds: DateAndTime now asSeconds) printString. configuration id: UUID new asString. + (repo includesVersionNamed: configuration name) + ifTrue: [self notify: ('The configuration does already exist in the repository you specified. If you proceed, it will be overwritten.\\Repository: {1}\Configuration: {2}\\Do you want to proceed anyway?' translated withCRs format: { repo description. configuration name })]. repo storeVersion: configuration. self inform: 'Saved ', configuration name]! From marcel.taeumel at hpi.de Thu Mar 4 16:12:51 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 4 Mar 2021 17:12:51 +0100 Subject: [squeak-dev] The Trunk: Collections-nice.925.mcz In-Reply-To: References: Message-ID: Hi all! This breaks subclassing for Interval. TextLineInterval is an example. Yet, it is used only in ST80, so I will change it there. What about #species? Or something similar? Do we really want to break subclassing on Interval? Best, Marcel Am 03.03.2021 02:14:24 schrieb commits at source.squeak.org : Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.925.mcz ==================== Summary ==================== Name: Collections-nice.925 Author: nice Time: 3 March 2021, 2:14:13.09562 am UUID: ee92856e-98d1-3a41-a3f2-3529927e7a02 Ancestors: Collections-jar.924 Distinguish questionable LimitedPrecisionInterval (those with Float bounds or step) from ordinary Interval of Integer, Fraction or ScaledDecimals. The main interest of having a specific class is to avoid crippling Interval with Float workarounds, for the rare use case. Explain some of the pitfalls of LimitedPrecisionInterval, and encourage alternatives in class comment, which is a second advantage of having a separate class. Abandon fuzzy inclusion logic, which is considered to introduce more discrepancies than it tries to solve See http://bugs.squeak.org/view.php?id=6455. and method #testSurprisingFuzzyInclusion Fix two other failing tests for Interval of Floats. Fix size so that (0.3 to: 1.2 by: 0.1) includes: 1.2. See https://github.com/dolphinsmalltalk/Dolphin/issues/1108 This makes size a bit less performant than super, a 3rd reason why a specific class is neat. Huh, that's more comments than code ;). =============== Diff against Collections-jar.924 =============== Item was changed: ----- Method: Interval class>>from:to: (in category 'instance creation') ----- from: startInteger to: stopInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of 1." + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision]) + ifTrue: [LimitedPrecisionInterval] + ifFalse: [Interval]) basicNew - ^self basicNew setFrom: startInteger to: stopInteger by: 1! Item was changed: ----- Method: Interval class>>from:to:by: (in category 'instance creation') ----- from: startInteger to: stopInteger by: stepInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of stepNumber." + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision or: [stepInteger hasLimitedPrecision]]) + ifTrue: [LimitedPrecisionInterval] + ifFalse: [Interval]) basicNew - ^self basicNew setFrom: startInteger to: stopInteger by: stepInteger! Item was changed: ----- Method: Interval>>indexOf:startingAt: (in category 'accessing') ----- indexOf: anElement startingAt: startIndex "startIndex is an positive integer, the collection index where the search is started." - "during the computation of val , floats are only used when the receiver contains floats" + | index | - | index val | (self rangeIncludes: anElement) ifFalse: [ ^0 ]. + index := (anElement - start / step) rounded + 1. - val := anElement - self first / self increment. - val isFloat - ifTrue: [ - (val - val rounded) abs * 100000000 < 1 ifFalse: [ ^0 ]. - index := val rounded + 1 ] - ifFalse: [ - val isInteger ifFalse: [ ^0 ]. - index := val + 1 ]. - "finally, the value of startIndex comes into play:" (index between: startIndex and: self size) ifFalse: [ ^0 ]. + (self at: index) = anElement ifFalse: [ ^0 ]. ^index! Item was added: + Interval subclass: #LimitedPrecisionInterval + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Sequenceable'! + + !LimitedPrecisionInterval commentStamp: 'nice 3/3/2021 01:47' prior: 0! + A LimitedPrecisionInterval is an Interval whose bounds or step haveLimitedPrecision. + Due to inexact arithmetic, special precautions must be taken in the implementation, + in order to avoid unconsistent and surprising behavior as much as possible. + + Despite those efforts, LimitedPrecisionInterval is full of pitfalls. + It is recommended to avoid using LimitedPrecisionInterval unless understanding those pitfalls. + For example, (0.2 to: 0.6 by: 0.1) last = 0.5. + This interval does not includes 0.6 because (0.1*4+0.2) is slightly greater than 0.6. + Another example is that (0.2 to: 0.6 by: 0.1) does not include 0.3 but a Float slightly greater. + + A usual workaround is to use an Integer interval, and reconstruct the Float inside the loop. + For example: + (0 to: 4) collect: [:i | 0.1*i+0.2]. + or better if we want to have 0.3 and 0.6: + (2 to: 6) collect: [:i | i / 10.0]. + Another workaround is to not use limited precision at all, but Fraction or ScaledDecimal when possible: + (1/10 to: 7/10 by: 1/10). + (0.1s to: 0.7s by: 0.1s). + + Yet another pitfall is that optimized to:by:do: might differ from (to:by:) do: + In the former case, repeated addition of increment is used, in the later, a multiplication is used. + Observe the differences: + Array streamContents: [:str | 0 to: 3 by: 0.3 do: [:e | str nextPut: e]]. + Array streamContents: [:str | (0 to: 3 by: 0.3) do: [:e | str nextPut: e]]. + + There are many more discrepancies, so use carefully, or not use it at all.! Item was added: + ----- Method: LimitedPrecisionInterval>>copyFrom:to: (in category 'copying') ----- + copyFrom: startIndex to: stopIndex + startIndex = 1 ifTrue: [^super copyFrom: startIndex to: stopIndex]. + stopIndex < startIndex ifTrue: [^self copyEmpty]. + ^Array new: stopIndex - startIndex + 1 streamContents: [:stream | + startIndex to: stopIndex do: [:i | stream nextPut: (self at: i)]]! Item was added: + ----- Method: LimitedPrecisionInterval>>last (in category 'accessing') ----- + last + "Refer to the comment in SequenceableCollection|last." + + ^start + (step * (self size - 1))! Item was added: + ----- Method: LimitedPrecisionInterval>>reversed (in category 'converting') ----- + reversed + "There is no guaranty that super reversed would contain same elements. + Answer an Array instead" + + ^Array new: self size streamContents: [:stream | self reverseDo: [:each | stream nextPut: each]]! Item was added: + ----- Method: LimitedPrecisionInterval>>size (in category 'accessing') ----- + size + "Answer how many elements the receiver contains." + + | candidateSize | + candidateSize := (stop - start / step max: 0) rounded. + step > 0 + ifTrue: [candidateSize * step + start <= stop ifTrue: [^candidateSize + 1]] + ifFalse: [candidateSize * step + start >= stop ifTrue: [^candidateSize + 1]]. + ^candidateSize! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 4 16:16:39 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 16:16:39 0000 Subject: [squeak-dev] The Trunk: ST80-mt.264.mcz Message-ID: Marcel Taeumel uploaded a new version of ST80 to project The Trunk: http://source.squeak.org/trunk/ST80-mt.264.mcz ==================== Summary ==================== Name: ST80-mt.264 Author: mt Time: 4 March 2021, 5:16:37.757335 pm UUID: 9600a535-6bad-a54c-80b6-902c4a8d87be Ancestors: ST80-mt.263 Work around the changes in Collections-nice.925 to make MVC work again. :-) =============== Diff against ST80-mt.263 =============== Item was added: + ----- Method: TextLineInterval class>>from:to:by: (in category 'instance creation') ----- + from: startInteger to: stopInteger by: stepInteger + "Answer an instance of me, starting at startNumber, ending at + stopNumber, and with an interval increment of stepNumber." + + ^ self basicNew + setFrom: startInteger + to: stopInteger + by: stepInteger! Item was changed: ----- Method: TextLineInterval class>>start:stop:internalSpaces:paddingWidth: (in category 'instance creation') ----- start: startInteger stop: stopInteger internalSpaces: spacesInteger paddingWidth: padWidthInteger "Answer an instance of me with the arguments as the start, stop points, number of spaces in the line, and width of the padding." | newSelf | + newSelf := self from: startInteger to: stopInteger by: 1. - newSelf := super from: startInteger to: stopInteger by: 1. ^newSelf internalSpaces: spacesInteger paddingWidth: padWidthInteger! From eliot.miranda at gmail.com Thu Mar 4 17:23:08 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 4 Mar 2021 09:23:08 -0800 Subject: [squeak-dev] Simulation guard crashes the image In-Reply-To: <1614848593348-0.post@n4.nabble.com> References: <1614848593348-0.post@n4.nabble.com> Message-ID: Hi Jaromir, > On Mar 4, 2021, at 1:03 AM, Jaromir Matas wrote: > > Hi, why the simulation guard in BlockClosure >> newProcess? > > It crashes the image when debugging e.g. [] fork. You hit Into -> Into -> > the the error window pops up, you cancel it (or Abandon...) and hit Into > again and the image is done :| I wish it was adequately documented. I can see some justification, that one doesn’t want simulation to “run away at . But I can also see the counter argument; one wants the debugger to simply be a way of inspecting any computation. If always struck me as odd but I’ve not had the courage to nuke it. > > In case there's no reason to keep the simulation guard why not just remove > it? Well, we have some choices: a) present the user with a notifier and offer that they proceed of not b) have a preference c) spawn a new debugger with the new process (so one now has two debuggers). d) nuke it e) leave it unchanged f...) ?... I like a. b is too hidden. d has the risk in rare circumstances of surprising behavior; after all someone must have been bitten at one point to want to put the simulation guard in. > Thanks, > > Squeak6.0alpha-20243-64bit-202003021730-Windows > Eliot _,,,^..^,,,_ (phone) > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > From eliot.miranda at gmail.com Thu Mar 4 17:35:14 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 4 Mar 2021 09:35:14 -0800 Subject: [squeak-dev] Simulation guard crashes the image In-Reply-To: <7906b282ca044bf3b907ac9c9ee4c2da@student.hpi.uni-potsdam.de> References: <7906b282ca044bf3b907ac9c9ee4c2da@student.hpi.uni-potsdam.de> Message-ID: <6E9AAE65-EB47-4BF7-8BCC-01BB6924B1DE@gmail.com> Hi Christoph, > On Mar 4, 2021, at 3:08 AM, Thiede, Christoph wrote: > >  > Hi Jaromir, > > > > thanks for your report. There are two problems here: > > > > 1. The usage of primitive 19 in #newProcess, which I'm glad not to be the only person to find it questionary. I already mentioned this here: http://forum.world.st/Just-another-debugger-bug-primitive-19-td5109411.html IMO the primitive does not make sense in this place, rather we should raise the simulation guard when primitiveSuspend or primitiveResume is invoked via simulation. Still, it is not necessarily a bad thing to let these things happen during simulation - that's why I would prefer to show some confirmation dialog instead of a warning. This is already on my to-do list and a solution for the second aspect should arrive in the Trunk during the next weeks. :-) > Good to hear. And your point about it not making sense makes me think. Given fast step, whether one hits the simulation guard or not doesn’t depend on whether one is debugging, but depends on whether one is at just the right point to enter doPrimitive:... rather than just perform:. So I agree; we should nuke it, with one proviso. We need to ensure that a newProcess gets Processor activePriority. ie we need to ensure that Processor activeProcess is always correct. Some more thought on this is needed. > > 2. Debugger chains crashing your image, which has already been discussed in great detail in http://forum.world.st/I-broke-the-debugger-td5110752.html#a5124736. I found the cause of the issue and have provided two possible solutions in this thread. Marcel and I are currently discussing the last details of the patch, but it should be complete soon and will arrive in the Trunk, probably together with the extended simulation guard as noted above! > > > > If you find further interesting bugs, please let us know them all. :D > > > > Best, > > Christoph > > Von: Squeak-dev im Auftrag von Jaromir Matas > Gesendet: Donnerstag, 4. März 2021 10:03:13 > An: squeak-dev at lists.squeakfoundation.org > Betreff: [squeak-dev] Simulation guard crashes the image > > Hi, why the simulation guard in BlockClosure >> newProcess? > > It crashes the image when debugging e.g. [] fork. You hit Into -> Into -> > the the error window pops up, you cancel it (or Abandon...) and hit Into > again and the image is done :| > > In case there's no reason to keep the simulation guard why not just remove > it? > Thanks, > > Squeak6.0alpha-20243-64bit-202003021730-Windows > > > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 4 17:55:08 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 17:55:08 0000 Subject: [squeak-dev] The Trunk: Collections-nice.929.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.929.mcz ==================== Summary ==================== Name: Collections-nice.929 Author: nice Time: 4 March 2021, 6:55:05.090663 pm UUID: 6e327843-eedc-4eeb-ba1b-0e14d4f40e56 Ancestors: Collections-nice.928 Don't hardcode Interval and LimitedPrecisionInterval so as to enable subclassing. Note: a subclass wanting to handle limited precision bounds or increment by itself should define: limitedPrecisionSpecies ^self. This is not the case of TextLineInterval that only ever see Integer bounds. =============== Diff against Collections-nice.928 =============== Item was changed: ----- Method: Interval class>>from:to: (in category 'instance creation') ----- from: startInteger to: stopInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of 1." ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision]) + ifTrue: [self limitedPrecisionSpecies] + ifFalse: [self]) basicNew - ifTrue: [LimitedPrecisionInterval] - ifFalse: [Interval]) basicNew setFrom: startInteger to: stopInteger by: 1! Item was changed: ----- Method: Interval class>>from:to:by: (in category 'instance creation') ----- from: startInteger to: stopInteger by: stepInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of stepNumber." ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision or: [stepInteger hasLimitedPrecision]]) + ifTrue: [self limitedPrecisionSpecies] + ifFalse: [self]) basicNew - ifTrue: [LimitedPrecisionInterval] - ifFalse: [Interval]) basicNew setFrom: startInteger to: stopInteger by: stepInteger! Item was added: + ----- Method: Interval class>>limitedPrecisionSpecies (in category 'instance creation') ----- + limitedPrecisionSpecies + "Answer a class able to handle limited precision bounds or step" + + ^LimitedPrecisionInterval! From nicolas.cellier.aka.nice at gmail.com Thu Mar 4 17:55:31 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Thu, 4 Mar 2021 18:55:31 +0100 Subject: [squeak-dev] The Trunk: Collections-nice.925.mcz In-Reply-To: References: Message-ID: Hi Marcel, yes sorry, I will fix it. I saw the red updateStream and failed to find the address of our CI. It should be more visible on squeak.org... Le jeu. 4 mars 2021 à 17:13, Marcel Taeumel a écrit : > > Hi all! > > This breaks subclassing for Interval. TextLineInterval is an example. Yet, it is used only in ST80, so I will change it there. > > What about #species? Or something similar? Do we really want to break subclassing on Interval? > > Best, > Marcel > > Am 03.03.2021 02:14:24 schrieb commits at source.squeak.org : > > Nicolas Cellier uploaded a new version of Collections to project The Trunk: > http://source.squeak.org/trunk/Collections-nice.925.mcz > > ==================== Summary ==================== > > Name: Collections-nice.925 > Author: nice > Time: 3 March 2021, 2:14:13.09562 am > UUID: ee92856e-98d1-3a41-a3f2-3529927e7a02 > Ancestors: Collections-jar.924 > > Distinguish questionable LimitedPrecisionInterval (those with Float bounds or step) from ordinary Interval of Integer, Fraction or ScaledDecimals. > > The main interest of having a specific class is to avoid crippling Interval with Float workarounds, for the rare use case. > > Explain some of the pitfalls of LimitedPrecisionInterval, and encourage alternatives in class comment, which is a second advantage of having a separate class. > > Abandon fuzzy inclusion logic, which is considered to introduce more discrepancies than it tries to solve > See http://bugs.squeak.org/view.php?id=6455. > and method #testSurprisingFuzzyInclusion > > Fix two other failing tests for Interval of Floats. > > Fix size so that (0.3 to: 1.2 by: 0.1) includes: 1.2. > See https://github.com/dolphinsmalltalk/Dolphin/issues/1108 > This makes size a bit less performant than super, a 3rd reason why a specific class is neat. > > Huh, that's more comments than code ;). > > =============== Diff against Collections-jar.924 =============== > > Item was changed: > ----- Method: Interval class>>from:to: (in category 'instance creation') ----- > from: startInteger to: stopInteger > "Answer an instance of me, starting at startNumber, ending at > stopNumber, and with an interval increment of 1." > > + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision]) > + ifTrue: [LimitedPrecisionInterval] > + ifFalse: [Interval]) basicNew > - ^self basicNew > setFrom: startInteger > to: stopInteger > by: 1! > > Item was changed: > ----- Method: Interval class>>from:to:by: (in category 'instance creation') ----- > from: startInteger to: stopInteger by: stepInteger > "Answer an instance of me, starting at startNumber, ending at > stopNumber, and with an interval increment of stepNumber." > > + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision or: [stepInteger hasLimitedPrecision]]) > + ifTrue: [LimitedPrecisionInterval] > + ifFalse: [Interval]) basicNew > - ^self basicNew > setFrom: startInteger > to: stopInteger > by: stepInteger! > > Item was changed: > ----- Method: Interval>>indexOf:startingAt: (in category 'accessing') ----- > indexOf: anElement startingAt: startIndex > "startIndex is an positive integer, the collection index where the search is started." > - "during the computation of val , floats are only used when the receiver contains floats" > > + | index | > - | index val | > (self rangeIncludes: anElement) ifFalse: [ ^0 ]. > + index := (anElement - start / step) rounded + 1. > - val := anElement - self first / self increment. > - val isFloat > - ifTrue: [ > - (val - val rounded) abs * 100000000 < 1 ifFalse: [ ^0 ]. > - index := val rounded + 1 ] > - ifFalse: [ > - val isInteger ifFalse: [ ^0 ]. > - index := val + 1 ]. > - "finally, the value of startIndex comes into play:" > (index between: startIndex and: self size) ifFalse: [ ^0 ]. > + (self at: index) = anElement ifFalse: [ ^0 ]. > ^index! > > Item was added: > + Interval subclass: #LimitedPrecisionInterval > + instanceVariableNames: '' > + classVariableNames: '' > + poolDictionaries: '' > + category: 'Collections-Sequenceable'! > + > + !LimitedPrecisionInterval commentStamp: 'nice 3/3/2021 01:47' prior: 0! > + A LimitedPrecisionInterval is an Interval whose bounds or step haveLimitedPrecision. > + Due to inexact arithmetic, special precautions must be taken in the implementation, > + in order to avoid unconsistent and surprising behavior as much as possible. > + > + Despite those efforts, LimitedPrecisionInterval is full of pitfalls. > + It is recommended to avoid using LimitedPrecisionInterval unless understanding those pitfalls. > + For example, (0.2 to: 0.6 by: 0.1) last = 0.5. > + This interval does not includes 0.6 because (0.1*4+0.2) is slightly greater than 0.6. > + Another example is that (0.2 to: 0.6 by: 0.1) does not include 0.3 but a Float slightly greater. > + > + A usual workaround is to use an Integer interval, and reconstruct the Float inside the loop. > + For example: > + (0 to: 4) collect: [:i | 0.1*i+0.2]. > + or better if we want to have 0.3 and 0.6: > + (2 to: 6) collect: [:i | i / 10.0]. > + Another workaround is to not use limited precision at all, but Fraction or ScaledDecimal when possible: > + (1/10 to: 7/10 by: 1/10). > + (0.1s to: 0.7s by: 0.1s). > + > + Yet another pitfall is that optimized to:by:do: might differ from (to:by:) do: > + In the former case, repeated addition of increment is used, in the later, a multiplication is used. > + Observe the differences: > + Array streamContents: [:str | 0 to: 3 by: 0.3 do: [:e | str nextPut: e]]. > + Array streamContents: [:str | (0 to: 3 by: 0.3) do: [:e | str nextPut: e]]. > + > + There are many more discrepancies, so use carefully, or not use it at all.! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>copyFrom:to: (in category 'copying') ----- > + copyFrom: startIndex to: stopIndex > + startIndex = 1 ifTrue: [^super copyFrom: startIndex to: stopIndex]. > + stopIndex < startIndex ifTrue: [^self copyEmpty]. > + ^Array new: stopIndex - startIndex + 1 streamContents: [:stream | > + startIndex to: stopIndex do: [:i | stream nextPut: (self at: i)]]! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>last (in category 'accessing') ----- > + last > + "Refer to the comment in SequenceableCollection|last." > + > + ^start + (step * (self size - 1))! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>reversed (in category 'converting') ----- > + reversed > + "There is no guaranty that super reversed would contain same elements. > + Answer an Array instead" > + > + ^Array new: self size streamContents: [:stream | self reverseDo: [:each | stream nextPut: each]]! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>size (in category 'accessing') ----- > + size > + "Answer how many elements the receiver contains." > + > + | candidateSize | > + candidateSize := (stop - start / step max: 0) rounded. > + step > 0 > + ifTrue: [candidateSize * step + start <= stop ifTrue: [^candidateSize + 1]] > + ifFalse: [candidateSize * step + start >= stop ifTrue: [^candidateSize + 1]]. > + ^candidateSize! > > > From commits at source.squeak.org Thu Mar 4 18:21:32 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 18:21:32 0000 Subject: [squeak-dev] The Trunk: Files-eem.187.mcz Message-ID: Eliot Miranda uploaded a new version of Files to project The Trunk: http://source.squeak.org/trunk/Files-eem.187.mcz ==================== Summary ==================== Name: Files-eem.187 Author: eem Time: 4 March 2021, 10:21:30.924262 am UUID: f14c3a5e-9f1b-4aff-9c3d-b239a4c9a5e9 Ancestors: Files-ul.186 Robustness with drop events. Put colleting directories and streams in a utility method for headless apps (drop events can be launch events on OSs such as macOS). Fix a speeling roore. =============== Diff against Files-ul.186 =============== Item was added: + ----- Method: FileDirectory class>>dropFilesAndDirectories: (in category 'dnd requests') ----- + dropFilesAndDirectories: numFiles + "Answer a sequence of directories and/or streams for a drop event. + The collect5ion may be empty." + ^(1 to: numFiles) + collect: + [:index | + (self requestDropDirectory: index) ifNil: + [FileStream requestDropStream: index]] + thenSelect: [:directoryOrStreamOrNil| directoryOrStreamOrNil notNil]! Item was changed: ----- Method: FileDirectory class>>requestDropDirectory: (in category 'dnd requests') ----- requestDropDirectory: dropIndex ^(FileStream primDropRequestFileName: dropIndex) ifNotNil: + [:dropFileName| | potentialDirectory | + potentialDirectory := self on: dropFileName. - [:dropFileDirdectoryName| | potentialDirectory | - potentialDirectory := self on: dropFileDirdectoryName. potentialDirectory exists ifTrue: [potentialDirectory]]! Item was changed: ----- Method: StandardFileStream>>requestDropStream: (in category 'dnd requests') ----- requestDropStream: dropIndex + "Answer a read-only stream for some file the user has just dropped onto Squeak, + or nil if dropIndex does not refer to a file." + ^(self class primDropRequestFileName: dropIndex) ifNotNil: + [:rawName| + name := rawName vmPathToSqueakPath. + fileID := self primDropRequestFileHandle: dropIndex. + fileID ifNotNil: + [self register. + rwmode := false. + buffer1 := String new: 1. + self enableReadBuffering. + self]]! - "Return a read-only stream for some file the user has just dropped onto Squeak." - | rawName | - rawName := self class primDropRequestFileName: dropIndex. - name := rawName vmPathToSqueakPath. - fileID := self primDropRequestFileHandle: dropIndex. - fileID == nil ifTrue:[^nil]. - self register. - rwmode := false. - buffer1 := String new: 1. - self enableReadBuffering - ! From commits at source.squeak.org Thu Mar 4 18:23:03 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 18:23:03 0000 Subject: [squeak-dev] The Trunk: Multilingual-eem.255.mcz Message-ID: Eliot Miranda uploaded a new version of Multilingual to project The Trunk: http://source.squeak.org/trunk/Multilingual-eem.255.mcz ==================== Summary ==================== Name: Multilingual-eem.255 Author: eem Time: 4 March 2021, 10:23:00.658047 am UUID: 55a1972b-10f3-4938-bc52-fa293e2b7973 Ancestors: Multilingual-ul.254 Cleanup related to Files-eem.187. BTW, seems to me that MultiByteFileStream no longer belongs in Multilingual, but would be better off in Files. =============== Diff against Multilingual-ul.254 =============== Item was changed: ----- Method: MultiByteFileStream>>requestDropStream: (in category 'private') ----- requestDropStream: dropIndex + "Override to install proper converter." - "Needs to install proper converter" + ^(super requestDropStream: dropIndex) ifNotNil: + [:result| - | result | - result := super requestDropStream: dropIndex. - result ifNotNil: [ converter ifNil: [self converter: UTF8TextConverter new]. + lineEndConvention ifNil: [ self detectLineEndConvention ]. + result]! - lineEndConvention ifNil: [ self detectLineEndConvention ] - ]. - ^result! From commits at source.squeak.org Thu Mar 4 18:26:10 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 18:26:10 0000 Subject: [squeak-dev] The Trunk: Morphic-eem.1734.mcz Message-ID: Eliot Miranda uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-eem.1734.mcz ==================== Summary ==================== Name: Morphic-eem.1734 Author: eem Time: 4 March 2021, 10:26:06.868233 am UUID: 065775fd-9942-4e59-99b9-0e9378c0590e Ancestors: Morphic-mt.1733 DropEvent cleanup related to Files-eem.187. =============== Diff against Morphic-mt.1733 =============== Item was removed: - ----- Method: HandMorph>>collectDropFilesAndDirectories: (in category 'private events') ----- - collectDropFilesAndDirectories: numFiles - - ^ (1 to: numFiles) collect: [:index | - (FileDirectory requestDropDirectory: index) - ifNil: [FileStream requestDropStream: index]]! Item was changed: ----- Method: HandMorph>>generateDropFilesEvent: (in category 'private events') ----- generateDropFilesEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer." | position buttons modifiers stamp numFiles dragType | stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Time eventMillisecondClock]. dragType := evtBuf third. position := evtBuf fourth @ evtBuf fifth. buttons := MouseEvent redButton. "hacked because necessary for correct mouseMoveDragging handling" modifiers := evtBuf sixth. buttons := buttons bitOr: (modifiers bitShift: 3). numFiles := evtBuf seventh. dragType caseOf: { [1] -> [ "dragEnter" externalDropMorph := TransferMorph new dragTransferType: #filesAndDirectories; source: self; passenger: (numFiles = 0 "Usually, numFiles and drop paths are delivered on dragDrop only. Still reserving this possibility for able host implementations." ifTrue: [self flag: #vmCapabilityMissing. 'Unknown host content' translated] + ifFalse: [FileDirectory dropFilesAndDirectories: numFiles]); - ifFalse: [self collectDropFilesAndDirectories: numFiles]); yourself. "During the drag operation, the host system is responsible for displaying the cursor." self grabMorph: externalDropMorph. self showTemporaryCursor: Cursor blank. externalDropMorph bottomRight: self topLeft. "Southeast area of the cursor is blocked by drawings from the source application. Display our drop morph at the opposite corner of the cursor." ]. [2] -> [ "dragMove" ^ MouseMoveEvent new setType: #mouseMove startPoint: self position endPoint: position trail: "{self position. position}"(self mouseDragTrailFrom: evtBuf) buttons: buttons hand: self stamp: stamp ]. [3] -> [ "dragLeave" externalDropMorph ifNotNil: #abandon. externalDropMorph := nil. self showTemporaryCursor: nil ]. [4] -> [ "dragDrop" | oldButtons | externalDropMorph ifNil: [ "dragDrop has been sent without prior dragging. This happens when the VM is configured as singleton application and has been called again (aka #launchDrop)." ^ self error: 'Launch drop for singleton Squeak not yet implemented.']. self showTemporaryCursor: nil. externalDropMorph passenger isString ifTrue: [ self flag: #vmCapabilityMissing. "See above." + externalDropMorph passenger: (FileDirectory dropFilesAndDirectories: numFiles)]. - externalDropMorph passenger: (self collectDropFilesAndDirectories: numFiles)]. externalDropMorph := nil. (Smalltalk classNamed: #DropFilesEvent) ifNotNil: [:eventClass | | classicEvent | "Generate classic DropFilesEvent, providing backward compatibility." classicEvent := eventClass new setPosition: position contents: numFiles hand: self. self processEvent: classicEvent. classicEvent wasHandled ifTrue: [^ nil]]. oldButtons := lastEventBuffer fifth bitOr: (lastEventBuffer sixth bitShift: 3). ^ MouseButtonEvent new setType: #mouseUp position: position which: (oldButtons bitXor: buttons) buttons: buttons nClicks: 0 hand: self stamp: stamp ]. [5] -> [ "drag request" "For dnd out. Not properly implemented at the moment." self shouldBeImplemented] }. ^ nil! From gettimothy at zoho.com Thu Mar 4 20:32:30 2021 From: gettimothy at zoho.com (gettimothy) Date: Thu, 04 Mar 2021 15:32:30 -0500 Subject: [squeak-dev] Morphic team, nice improvement during installer runs. The progress bar stays in top right... In-Reply-To: <1614871814882-0.post@n4.nabble.com> References: <177642fc86e.114e3871628639.4614723699233167822@zoho.com> <1614871814882-0.post@n4.nabble.com> Message-ID: <177fef11c95.d49b7eee24082.8241058649473511534@zoho.com> Hi Marcel, By "top right" I mean the top right corner of the World. On older Squeaks the progress bar would jump about and resize as tghe packages installed. cheers, ---- On Thu, 04 Mar 2021 10:30:14 -0500 marcel.taeumel wrote ---- Hi, there. What do you mean "top right"? The labels should be "top left" aligned with their bars unless they are bigger than the bars. In that case, they get centered. Not sure why this is what we want. For nested bars, UI still seems to jiggle between topLeft and center sometimes. Best, Marcel -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 4 20:48:27 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 20:48:27 0000 Subject: [squeak-dev] The Trunk: KernelTests-nice.393.mcz Message-ID: Nicolas Cellier uploaded a new version of KernelTests to project The Trunk: http://source.squeak.org/trunk/KernelTests-nice.393.mcz ==================== Summary ==================== Name: KernelTests-nice.393 Author: nice Time: 4 March 2021, 9:48:25.332412 pm UUID: 17415633-8a99-47e7-a3eb-f736b66348ca Ancestors: KernelTests-eem.392 Test some log2 features (exactness and overflow/underflow protection) Also exhibit potential weakness near unity. =============== Diff against KernelTests-eem.392 =============== Item was added: + ----- Method: FloatTest>>assert:equals:withinUlp: (in category 'asserting') ----- + assert: expected equals: actual withinUlp: maxUlp + self assert: (expected - actual) abs <= (maxUlp * expected asFloat ulp)! Item was added: + ----- Method: FloatTest>>testLog2near1 (in category 'tests - mathematical functions') ----- + testLog2near1 + self assert: 1.0 predecessor ln / 2 ln equals: 1.0 predecessor log2 withinUlp: 2. + self assert: 1.0 successor ln / 2 ln equals: 1.0 successor log2 withinUlp: 2! Item was added: + ----- Method: NumberTest>>testExactLog2 (in category 'tests') ----- + testExactLog2 + -10 to: 10 do: [:i | self assert: i equals: (2 raisedToInteger: i) log2]. + Float emin - Float precision + 1 to: Float emax do: [:i | self assert: i equals: (1.0 timesTwoPower: i) log2].! Item was added: + ----- Method: NumberTest>>testLog2doesNotOverflow (in category 'tests') ----- + testLog2doesNotOverflow + "Note: though this is not a strict identity, we can use strict Float equality here" + self assert: 3000.0 equals: ((1 bitShift: 3000) - 1) log2. + self assert: 1500.0 equals: (((1 bitShift: 3000) - 1) / (1 bitShift: 1500)) log2.! Item was added: + ----- Method: NumberTest>>testLog2doesNotUnderflow (in category 'tests') ----- + testLog2doesNotUnderflow + "Note: though this is not a strict identity, we can use strict Float equality here" + self assert: -2000.0 equals: ((1 bitShift: 2000) - 1) reciprocal log2! From commits at source.squeak.org Thu Mar 4 21:10:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 21:10:33 0000 Subject: [squeak-dev] The Trunk: Kernel-nice.1377.mcz Message-ID: Nicolas Cellier uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-nice.1377.mcz ==================== Summary ==================== Name: Kernel-nice.1377 Author: nice Time: 4 March 2021, 10:10:29.295967 pm UUID: ddcc60af-76a7-4d50-b5e3-ebf4ff39eb07 Ancestors: Kernel-nice.1376 Fix log2 implementation to make it robust in the neighbourhood of 1.0. Let aFloat isPowerOfTwo answer true if its value is a power of two. There is no obvious reason nor documentation why it should be false, and the implementation is neat. Introduce isDenormal to test if a Float is denormalized. A denormalized Float is one with minimal exponent, and significand part gradually loosing significant bits (a.k.a. gradual underflow). I.O.W, denormals loose precision. If we would define: Float>>precision ^(self exponent - Float emin min: 0) + self class precision Then, we would have Float fminNormalized precision = Float precision. Float fminNormalized predecessor = (Float precision - 1). Float fminDenormalized precision = 1. =============== Diff against Kernel-nice.1376 =============== Item was added: + ----- Method: Float>>isDenormal (in category 'testing') ----- + isDenormal + "Return true if the receiver is a denormal." + + ^ self exponent < self class emin and: [self isZero not]! Item was changed: ----- Method: Float>>isPowerOfTwo (in category 'testing') ----- isPowerOfTwo + "Return true if the receiver is an integral power of two." + ^self significand = 1.0! - "Return true if the receiver is an integral power of two. - Floats never return true here." - ^false! Item was changed: ----- Method: Float>>log2 (in category 'mathematical functions') ----- log2 "Answer the base 2 logarithm of the receiver. Arrange to answer exact result in case of exact power of 2." + | s | + s := self significand. + ^s > 1.3333333333333333 + ifTrue: [(0.5 * s) ln / Ln2 + (1 + self exponent)] + ifFalse: [s ln / Ln2 + self exponent]! - ^ self significand ln / Ln2 + self exponent! From commits at source.squeak.org Thu Mar 4 21:13:12 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 21:13:12 0000 Subject: [squeak-dev] The Trunk: Morphic-eem.1735.mcz Message-ID: Eliot Miranda uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-eem.1735.mcz ==================== Summary ==================== Name: Morphic-eem.1735 Author: eem Time: 4 March 2021, 1:13:03.650992 pm UUID: 7ba0bde5-351e-b94c-a4b5-a4846f3f907c Ancestors: Morphic-eem.1734 Use the constants on the class side of MouseEvent (adding numButtons to them) when creating the button field that (incredibly annoyingly) combines mouse buttons and modifier keys. This is a necessary first step to increasing the nu,ber of buttons to include the moveLeft and moveRight buttons on modern gaming mice. =============== Diff against Morphic-eem.1734 =============== Item was changed: ----- Method: HandMorph>>generateDropFilesEvent: (in category 'private events') ----- generateDropFilesEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer." | position buttons modifiers stamp numFiles dragType | stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Time eventMillisecondClock]. dragType := evtBuf third. position := evtBuf fourth @ evtBuf fifth. buttons := MouseEvent redButton. "hacked because necessary for correct mouseMoveDragging handling" modifiers := evtBuf sixth. + buttons := buttons bitOr: (modifiers bitShift: MouseEvent numButtons). - buttons := buttons bitOr: (modifiers bitShift: 3). numFiles := evtBuf seventh. dragType caseOf: { [1] -> [ "dragEnter" externalDropMorph := TransferMorph new dragTransferType: #filesAndDirectories; source: self; passenger: (numFiles = 0 "Usually, numFiles and drop paths are delivered on dragDrop only. Still reserving this possibility for able host implementations." ifTrue: [self flag: #vmCapabilityMissing. 'Unknown host content' translated] ifFalse: [FileDirectory dropFilesAndDirectories: numFiles]); yourself. "During the drag operation, the host system is responsible for displaying the cursor." self grabMorph: externalDropMorph. self showTemporaryCursor: Cursor blank. externalDropMorph bottomRight: self topLeft. "Southeast area of the cursor is blocked by drawings from the source application. Display our drop morph at the opposite corner of the cursor." ]. [2] -> [ "dragMove" ^ MouseMoveEvent new setType: #mouseMove startPoint: self position endPoint: position trail: "{self position. position}"(self mouseDragTrailFrom: evtBuf) buttons: buttons hand: self stamp: stamp ]. [3] -> [ "dragLeave" externalDropMorph ifNotNil: #abandon. externalDropMorph := nil. self showTemporaryCursor: nil ]. [4] -> [ "dragDrop" | oldButtons | externalDropMorph ifNil: [ "dragDrop has been sent without prior dragging. This happens when the VM is configured as singleton application and has been called again (aka #launchDrop)." ^ self error: 'Launch drop for singleton Squeak not yet implemented.']. self showTemporaryCursor: nil. externalDropMorph passenger isString ifTrue: [ self flag: #vmCapabilityMissing. "See above." externalDropMorph passenger: (FileDirectory dropFilesAndDirectories: numFiles)]. externalDropMorph := nil. (Smalltalk classNamed: #DropFilesEvent) ifNotNil: [:eventClass | | classicEvent | "Generate classic DropFilesEvent, providing backward compatibility." classicEvent := eventClass new setPosition: position contents: numFiles hand: self. self processEvent: classicEvent. classicEvent wasHandled ifTrue: [^ nil]]. oldButtons := lastEventBuffer fifth + bitOr: (lastEventBuffer sixth bitShift: MouseEvent numButtons). - bitOr: (lastEventBuffer sixth bitShift: 3). ^ MouseButtonEvent new setType: #mouseUp position: position which: (oldButtons bitXor: buttons) buttons: buttons nClicks: 0 hand: self stamp: stamp ]. [5] -> [ "drag request" "For dnd out. Not properly implemented at the moment." self shouldBeImplemented] }. ^ nil! Item was changed: ----- Method: HandMorph>>generateKeyboardEvent: (in category 'private events') ----- generateKeyboardEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer" | buttons modifiers type pressType stamp keyValue | stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Sensor eventTimeNow]. pressType := evtBuf fourth. pressType = EventKeyDown ifTrue: [type := #keyDown]. pressType = EventKeyUp ifTrue: [type := #keyUp]. pressType = EventKeyChar ifTrue: [type := #keystroke]. modifiers := evtBuf fifth. + buttons := (modifiers bitShift: MouseEvent numButtons) bitOr: (lastMouseEvent buttons bitAnd: MouseEvent anyButton). - buttons := (modifiers bitShift: 3) bitOr: (lastMouseEvent buttons bitAnd: 7). type = #keystroke ifTrue: [keyValue := (self keyboardInterpreter nextCharFrom: Sensor firstEvt: evtBuf) asInteger] ifFalse: [keyValue := evtBuf third]. ^ KeyboardEvent new setType: type buttons: buttons position: self position keyValue: keyValue hand: self stamp: stamp. ! Item was changed: ----- Method: HandMorph>>generateMouseEvent: (in category 'private events') ----- generateMouseEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer" | position buttons modifiers type trail stamp oldButtons evtChanged | evtBuf first = lastEventBuffer first ifTrue: ["Workaround for Mac VM bug, *always* generating 3 events on clicks" evtChanged := false. 3 to: evtBuf size do: [:i | (lastEventBuffer at: i) = (evtBuf at: i) ifFalse: [evtChanged := true]]. evtChanged ifFalse: [^nil]]. stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Sensor eventTimeNow]. position := evtBuf third @ evtBuf fourth. buttons := evtBuf fifth. modifiers := evtBuf sixth. type := buttons = 0 + ifTrue: + [lastEventBuffer fifth = 0 + ifTrue: [#mouseMove] "this time no button and previously no button .. just mouse move" + ifFalse: [#mouseUp]] "this time no button but previously some button ... therefore button was released" + ifFalse: + [buttons = lastEventBuffer fifth + ifTrue: [#mouseMove] "button states are the same .. now and past .. therfore a mouse movement" + ifFalse: "button states are different .. button was pressed or released" + [buttons > lastEventBuffer fifth - ifTrue:[ - lastEventBuffer fifth = 0 - ifTrue: [#mouseMove] "this time no button and previously no button .. just mouse move" - ifFalse: [#mouseUp] "this time no button but previously some button ... therefore button was released" - ] - ifFalse:[ - buttons = lastEventBuffer fifth - ifTrue: [#mouseMove] "button states are the same .. now and past .. therfore a mouse movement" - ifFalse: [ "button states are different .. button was pressed or released" - buttons > lastEventBuffer fifth ifTrue: [#mouseDown] + ifFalse:[#mouseUp]]]. + buttons := buttons bitOr: (modifiers bitShift: MouseEvent numButtons). + oldButtons := lastEventBuffer fifth bitOr: (lastEventBuffer sixth bitShift: MouseEvent numButtons). - ifFalse:[#mouseUp]. - ]. - ]. - buttons := buttons bitOr: (modifiers bitShift: 3). - oldButtons := lastEventBuffer fifth - bitOr: (lastEventBuffer sixth bitShift: 3). lastEventBuffer := evtBuf. + type == #mouseMove ifTrue: + [trail := self mouseTrailFrom: evtBuf. + ^MouseMoveEvent new + setType: type + startPoint: self position + endPoint: trail last + trail: trail + buttons: buttons + hand: self + stamp: stamp]. - type == #mouseMove - ifTrue: - [trail := self mouseTrailFrom: evtBuf. - ^MouseMoveEvent new - setType: type - startPoint: (self position) - endPoint: trail last - trail: trail - buttons: buttons - hand: self - stamp: stamp]. ^MouseButtonEvent new setType: type position: position which: (oldButtons bitXor: buttons) buttons: buttons nClicks: (evtBuf seventh ifNil: [0]) hand: self stamp: stamp! Item was changed: ----- Method: HandMorph>>showEvent: (in category 'events-debugging') ----- showEvent: anEvent "Show details about the event on the display form. Useful for debugging." + "ShowEvents := true" + "ShowEvents := false" - | message borderWidth | ShowEvents == true ifFalse: [^ self]. borderWidth := 5. message := String streamContents: [:strm | strm nextPutAll: '[HandMorph >> #showEvent:]'; cr; nextPutAll: 'event'; tab; tab; tab; tab; nextPutAll: anEvent printString; cr; nextPutAll: 'keyboard focus'; tab; tab; nextPutAll: self keyboardFocus printString; cr; nextPutAll: 'mouse focus'; tab; tab; nextPutAll: self mouseFocus printString]. message := message asDisplayText foregroundColor: Color black backgroundColor: Color white. "Offset to support multiple hands debugging." Display fill: (0 @ 0 extent: message form extent + (borderWidth asPoint * 2)) rule: Form over fillColor: Color white. message displayOn: Display at: borderWidth asPoint + (0 @ ((owner hands indexOf: self) - 1 * message form height)).! Item was added: + ----- Method: MouseEvent class>>numButtons (in category 'constants') ----- + numButtons + "We support three button mice." + ^3! From commits at source.squeak.org Thu Mar 4 22:52:42 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 22:52:42 0000 Subject: [squeak-dev] The Trunk: Morphic-eem.1736.mcz Message-ID: Eliot Miranda uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-eem.1736.mcz ==================== Summary ==================== Name: Morphic-eem.1736 Author: eem Time: 4 March 2021, 2:52:33.343618 pm UUID: b52e696e-9ad9-f840-b828-4bd8671b59c1 Ancestors: Morphic-eem.1735 More use of MouseEvent class side mouse button constants to prepare for more mouse buttons on gaming mice. =============== Diff against Morphic-eem.1735 =============== Item was changed: ----- Method: UserInputEvent>>commandKeyPressed (in category 'modifier state') ----- commandKeyPressed "Answer true if the command key on the keyboard was being held down when this event occurred." + ^buttons anyMask: MouseEvent numButtons + 3! - ^ buttons anyMask: 64! Item was changed: ----- Method: UserInputEvent>>controlKeyPressed (in category 'modifier state') ----- controlKeyPressed + "Answer if the control key on the keyboard was being held down when this event occurred." - "Answer true if the control key on the keyboard was being held down when this event occurred." + ^buttons anyMask: (1 bitShift: MouseEvent numButtons + 1)! - ^ buttons anyMask: 16! Item was changed: ----- Method: UserInputEvent>>shiftPressed (in category 'modifier state') ----- shiftPressed "Answer true if the shift key on the keyboard was being held down when this event occurred." + ^buttons anyMask: (1 bitShift: MouseEvent numButtons) - ^ buttons anyMask: 8 ! From commits at source.squeak.org Thu Mar 4 23:03:32 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 4 Mar 2021 23:03:32 0000 Subject: [squeak-dev] The Trunk: Kernel-eem.1378.mcz Message-ID: Eliot Miranda uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-eem.1378.mcz ==================== Summary ==================== Name: Kernel-eem.1378 Author: eem Time: 4 March 2021, 3:03:26.648613 pm UUID: 670311c0-11d4-4449-8c70-61d25280506f Ancestors: Kernel-nice.1377 Use the class side methods of MouseEvent to compute the (incredibly annoying) conflation of mouse buttons and modifier keys in events. This is a necessary first step in increasing the number of mouse buttons to support modern gaming mice. =============== Diff against Kernel-nice.1377 =============== Item was changed: ----- Method: EventSensor>>commandKeyPressed (in category 'modifier keys') ----- commandKeyPressed "Answer whether the command key on the keyboard is being held down." + ^ self peekButtons anyMask: MouseEvent numButtons + 3! - ^ self peekButtons anyMask: 64! Item was changed: ----- Method: EventSensor>>controlKeyPressed (in category 'modifier keys') ----- controlKeyPressed "Answer whether the control key on the keyboard is being held down." + ^self peekButtons anyMask: (1 bitShift: MouseEvent numButtons + 1)! - ^ self peekButtons anyMask: 16! Item was changed: ----- Method: EventSensor>>processKeyboardEvent: (in category 'private-I/O') ----- processKeyboardEvent: evt "process a keyboard event, updating EventSensor state" - | charCode pressCode | "Never update keyboardBuffer if we have an eventQueue active" + mouseButtons := (mouseButtons bitAnd: MouseEvent anyButton) bitOr: ((evt at: 5) bitShift: MouseEvent numButtons). - mouseButtons := (mouseButtons bitAnd: 7) bitOr: ((evt at: 5) bitShift: 3). + (evt at: 3) ifNotNil: "extra characters not handled in MVC" + [:charCode| | pressCode | + (pressCode := evt at: 4) = EventKeyChar ifTrue: "key down/up not handled in MVC" + ["mix in modifiers" + keyboardBuffer nextPut: (charCode bitOr: ((evt at: 5) bitShift: 8))]]! - charCode := evt at: 3. - charCode = nil ifTrue:[^self]. "extra characters not handled in MVC" - pressCode := evt at: 4. - pressCode = EventKeyChar ifFalse:[^self]. "key down/up not handled in MVC" - "mix in modifiers" - charCode := charCode bitOr: ((evt at: 5) bitShift: 8). - keyboardBuffer nextPut: charCode.! Item was changed: ----- Method: EventSensor>>processMouseEvent: (in category 'private-I/O') ----- processMouseEvent: evt "process a mouse event, updating EventSensor state" | modifiers buttons mapped | mousePosition := (evt at: 3) @ (evt at: 4). buttons := evt at: 5. modifiers := evt at: 6. mapped := self mapButtons: buttons modifiers: modifiers. + mouseButtons := mapped bitOr: (modifiers bitShift: MouseEvent numButtons)! - mouseButtons := mapped bitOr: (modifiers bitShift: 3).! Item was changed: ----- Method: EventSensor>>processMouseWheelEvent: (in category 'private-I/O') ----- processMouseWheelEvent: evt "process a mouse wheel event, updating EventSensor state" | modifiers buttons mapped | mouseWheelDelta := mouseWheelDelta + ((evt at: 3) @ (evt at: 4)). buttons := evt at: 5. modifiers := evt at: 6. mapped := self mapButtons: buttons modifiers: modifiers. + mouseButtons := mapped bitOr: (modifiers bitShift: MouseEvent numButtons)! - mouseButtons := mapped bitOr: (modifiers bitShift: 3).! Item was changed: ----- Method: EventSensor>>shiftPressed (in category 'modifier keys') ----- shiftPressed "Answer whether the shift key on the keyboard is being held down." + ^ self peekButtons anyMask: (1 bitShift: MouseEvent numButtons)! - ^ self peekButtons anyMask: 8 - ! From commits at source.squeak.org Fri Mar 5 00:03:59 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 00:03:59 0000 Subject: [squeak-dev] The Trunk: Morphic-eem.1737.mcz Message-ID: Eliot Miranda uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-eem.1737.mcz ==================== Summary ==================== Name: Morphic-eem.1737 Author: eem Time: 4 March 2021, 4:03:54.375892 pm UUID: 789562ea-966c-8f4e-9941-5576a9653b4d Ancestors: Morphic-eem.1736 Have HandMorph>>showEvent: avoid scribbling over the DockingBar. =============== Diff against Morphic-eem.1736 =============== Item was changed: ----- Method: HandMorph>>generateMouseEvent: (in category 'private events') ----- generateMouseEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer" | position buttons modifiers type trail stamp oldButtons evtChanged | + evtBuf first = lastEventBuffer first ifTrue: + ["Workaround for Mac VM bug, *always* generating 3 events on clicks" + evtChanged := false. + 3 to: evtBuf size do: + [:i | (lastEventBuffer at: i) = (evtBuf at: i) ifFalse: [evtChanged := true]]. + evtChanged ifFalse: [^nil]]. - evtBuf first = lastEventBuffer first - ifTrue: - ["Workaround for Mac VM bug, *always* generating 3 events on clicks" - - evtChanged := false. - 3 to: evtBuf size - do: [:i | (lastEventBuffer at: i) = (evtBuf at: i) ifFalse: [evtChanged := true]]. - evtChanged ifFalse: [^nil]]. stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Sensor eventTimeNow]. position := evtBuf third @ evtBuf fourth. buttons := evtBuf fifth. modifiers := evtBuf sixth. type := buttons = 0 ifTrue: [lastEventBuffer fifth = 0 ifTrue: [#mouseMove] "this time no button and previously no button .. just mouse move" ifFalse: [#mouseUp]] "this time no button but previously some button ... therefore button was released" ifFalse: [buttons = lastEventBuffer fifth ifTrue: [#mouseMove] "button states are the same .. now and past .. therfore a mouse movement" ifFalse: "button states are different .. button was pressed or released" [buttons > lastEventBuffer fifth ifTrue: [#mouseDown] ifFalse:[#mouseUp]]]. buttons := buttons bitOr: (modifiers bitShift: MouseEvent numButtons). oldButtons := lastEventBuffer fifth bitOr: (lastEventBuffer sixth bitShift: MouseEvent numButtons). lastEventBuffer := evtBuf. type == #mouseMove ifTrue: [trail := self mouseTrailFrom: evtBuf. ^MouseMoveEvent new setType: type startPoint: self position endPoint: trail last trail: trail buttons: buttons hand: self stamp: stamp]. ^MouseButtonEvent new setType: type position: position which: (oldButtons bitXor: buttons) buttons: buttons nClicks: (evtBuf seventh ifNil: [0]) hand: self stamp: stamp! Item was changed: ----- Method: HandMorph>>showEvent: (in category 'events-debugging') ----- showEvent: anEvent "Show details about the event on the display form. Useful for debugging." "ShowEvents := true" "ShowEvents := false" + | message borderWidth heightOffset | - | message borderWidth | ShowEvents == true ifFalse: [^ self]. borderWidth := 5. message := String streamContents: [:strm | strm nextPutAll: '[HandMorph >> #showEvent:]'; cr; nextPutAll: 'event'; tab; tab; tab; tab; nextPutAll: anEvent printString; cr; nextPutAll: 'keyboard focus'; tab; tab; nextPutAll: self keyboardFocus printString; cr; nextPutAll: 'mouse focus'; tab; tab; nextPutAll: self mouseFocus printString]. message := message asDisplayText foregroundColor: Color black backgroundColor: Color white. + heightOffset := (owner submorphs detect: [:m| m isDockingBar] ifNone: []) + ifNil: [0] + ifNotNil: [:m| m height]. - "Offset to support multiple hands debugging." + Display fill: (0 @ heightOffset extent: message form extent + (borderWidth asPoint * 2)) rule: Form over fillColor: Color white. + message displayOn: Display at: (borderWidth @ heightOffset) + (0 @ ((owner hands indexOf: self) - 1 * message form height)).! - Display fill: (0 @ 0 extent: message form extent + (borderWidth asPoint * 2)) rule: Form over fillColor: Color white. - message displayOn: Display at: borderWidth asPoint + (0 @ ((owner hands indexOf: self) - 1 * message form height)).! Item was added: + ----- Method: MouseButtonEvent>>moveRightButtonChanged (in category 'accessing') ----- + moveRightButtonChanged + "Answer if the move right mouse button has changed. This is the move left button on gaming mice." + + ^ whichButton anyMask: 16! From commits at source.squeak.org Fri Mar 5 02:44:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 02:44:33 0000 Subject: [squeak-dev] The Trunk: Kernel-eem.1379.mcz Message-ID: Eliot Miranda uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-eem.1379.mcz ==================== Summary ==================== Name: Kernel-eem.1379 Author: eem Time: 4 March 2021, 6:44:30.30655 pm UUID: f2d03504-03c9-e747-933d-f16f82d99091 Ancestors: Kernel-eem.1378 Fix terrible regression introduced in Kernel-eem.1378. I do apologize. =============== Diff against Kernel-eem.1378 =============== Item was changed: ----- Method: EventSensor>>commandKeyPressed (in category 'modifier keys') ----- commandKeyPressed "Answer whether the command key on the keyboard is being held down." + ^ self peekButtons anyMask: (1 bitShift: MouseEvent numButtons + 3)! - ^ self peekButtons anyMask: MouseEvent numButtons + 3! From commits at source.squeak.org Fri Mar 5 02:46:20 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 02:46:20 0000 Subject: [squeak-dev] The Trunk: Morphic-eem.1738.mcz Message-ID: Eliot Miranda uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-eem.1738.mcz ==================== Summary ==================== Name: Morphic-eem.1738 Author: eem Time: 4 March 2021, 6:46:15.090193 pm UUID: a8d1af56-a7d2-c046-94fd-e0cc4184f8f1 Ancestors: Morphic-eem.1737 Fix terrible regression in Morphic-eem.1737. I do apologize!! =============== Diff against Morphic-eem.1737 =============== Item was changed: ----- Method: UserInputEvent>>commandKeyPressed (in category 'modifier state') ----- commandKeyPressed "Answer true if the command key on the keyboard was being held down when this event occurred." + ^buttons anyMask: (1 bitShift: MouseEvent numButtons + 3)! - ^buttons anyMask: MouseEvent numButtons + 3! From eliot.miranda at gmail.com Fri Mar 5 03:00:57 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 4 Mar 2021 19:00:57 -0800 Subject: [squeak-dev] Removing the old pre-event-driven input polling input primitives Message-ID: Hi all, I'm just checking. It seems to me that primitives 90, 107, & 108, oldPrimMousePt, oldPrimMouseButtons, & oldPrimKbdNext, have been obsolete for a very long time. Am I correct? Is there any possibility these could be relevant to a Cog VM, that is any image from 4.0 on? WOuld removing the support for these primitives form the VM potentially impact porting old Etoys projects? Any other potential impacts? I'd like to nuke the code to ease extending the VM to support modern mice, which have many more buttons available, because it makes things unnecessarily complicated. _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Fri Mar 5 07:43:45 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 08:43:45 +0100 Subject: [squeak-dev] Removing the old pre-event-driven input polling input primitives In-Reply-To: References: Message-ID: Hi Eliot. +1 Yes, I think that we do not need those primitives anymore. We re-implemented that event-peeking interface through primitive 94 so that MVC keeps on working. Since Etoys builds on top of Morphic, which is not affected at all, we should be fine. Even OLPCVirtualSensor should keep on working. Take a look at all those #peek* methods in EventSensor. Most of them are already an extension for *ST80 :-) Go nuke those primitives. :-) Yet, we would not have any fallback code in #primGetNextEvent: anymore, which is kind of impossible anyway, right? I can help you with adapting higher-level event code for mice with many buttons. Best, Marcel Am 05.03.2021 04:01:23 schrieb Eliot Miranda : Hi all,     I'm just checking.  It seems to me that primitives 90, 107, & 108, oldPrimMousePt, oldPrimMouseButtons, & oldPrimKbdNext, have been obsolete for a very long time.  Am I correct? Is there any possibility these could be relevant to a Cog VM, that is any image from 4.0 on?  WOuld removing the support for these primitives form the VM potentially impact porting old Etoys projects?  Any other potential impacts? I'd like to nuke the code to ease extending the VM to support modern mice, which have many more buttons available, because it makes things unnecessarily complicated. _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Fri Mar 5 07:50:13 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 08:50:13 +0100 Subject: [squeak-dev] The Trunk: Kernel-eem.1378.mcz In-Reply-To: References: Message-ID: Note that, at some point, we might want to move both EventSensor and event classes (e.g. MouseEvent) into a common package. Because leaving it like this would make Kernel depending on Morphic. :-) I am still looking for a name (and overall responsibilities) for such a package... Best, Marcel Am 05.03.2021 00:03:41 schrieb commits at source.squeak.org : Eliot Miranda uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-eem.1378.mcz ==================== Summary ==================== Name: Kernel-eem.1378 Author: eem Time: 4 March 2021, 3:03:26.648613 pm UUID: 670311c0-11d4-4449-8c70-61d25280506f Ancestors: Kernel-nice.1377 Use the class side methods of MouseEvent to compute the (incredibly annoying) conflation of mouse buttons and modifier keys in events. This is a necessary first step in increasing the number of mouse buttons to support modern gaming mice. =============== Diff against Kernel-nice.1377 =============== Item was changed: ----- Method: EventSensor>>commandKeyPressed (in category 'modifier keys') ----- commandKeyPressed "Answer whether the command key on the keyboard is being held down." + ^ self peekButtons anyMask: MouseEvent numButtons + 3! - ^ self peekButtons anyMask: 64! Item was changed: ----- Method: EventSensor>>controlKeyPressed (in category 'modifier keys') ----- controlKeyPressed "Answer whether the control key on the keyboard is being held down." + ^self peekButtons anyMask: (1 bitShift: MouseEvent numButtons + 1)! - ^ self peekButtons anyMask: 16! Item was changed: ----- Method: EventSensor>>processKeyboardEvent: (in category 'private-I/O') ----- processKeyboardEvent: evt "process a keyboard event, updating EventSensor state" - | charCode pressCode | "Never update keyboardBuffer if we have an eventQueue active" + mouseButtons := (mouseButtons bitAnd: MouseEvent anyButton) bitOr: ((evt at: 5) bitShift: MouseEvent numButtons). - mouseButtons := (mouseButtons bitAnd: 7) bitOr: ((evt at: 5) bitShift: 3). + (evt at: 3) ifNotNil: "extra characters not handled in MVC" + [:charCode| | pressCode | + (pressCode := evt at: 4) = EventKeyChar ifTrue: "key down/up not handled in MVC" + ["mix in modifiers" + keyboardBuffer nextPut: (charCode bitOr: ((evt at: 5) bitShift: 8))]]! - charCode := evt at: 3. - charCode = nil ifTrue:[^self]. "extra characters not handled in MVC" - pressCode := evt at: 4. - pressCode = EventKeyChar ifFalse:[^self]. "key down/up not handled in MVC" - "mix in modifiers" - charCode := charCode bitOr: ((evt at: 5) bitShift: 8). - keyboardBuffer nextPut: charCode.! Item was changed: ----- Method: EventSensor>>processMouseEvent: (in category 'private-I/O') ----- processMouseEvent: evt "process a mouse event, updating EventSensor state" | modifiers buttons mapped | mousePosition := (evt at: 3) @ (evt at: 4). buttons := evt at: 5. modifiers := evt at: 6. mapped := self mapButtons: buttons modifiers: modifiers. + mouseButtons := mapped bitOr: (modifiers bitShift: MouseEvent numButtons)! - mouseButtons := mapped bitOr: (modifiers bitShift: 3).! Item was changed: ----- Method: EventSensor>>processMouseWheelEvent: (in category 'private-I/O') ----- processMouseWheelEvent: evt "process a mouse wheel event, updating EventSensor state" | modifiers buttons mapped | mouseWheelDelta := mouseWheelDelta + ((evt at: 3) @ (evt at: 4)). buttons := evt at: 5. modifiers := evt at: 6. mapped := self mapButtons: buttons modifiers: modifiers. + mouseButtons := mapped bitOr: (modifiers bitShift: MouseEvent numButtons)! - mouseButtons := mapped bitOr: (modifiers bitShift: 3).! Item was changed: ----- Method: EventSensor>>shiftPressed (in category 'modifier keys') ----- shiftPressed "Answer whether the shift key on the keyboard is being held down." + ^ self peekButtons anyMask: (1 bitShift: MouseEvent numButtons)! - ^ self peekButtons anyMask: 8 - ! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Fri Mar 5 07:52:57 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 08:52:57 +0100 Subject: [squeak-dev] The Trunk: Morphic-eem.1735.mcz In-Reply-To: References: Message-ID: Finally! A name for that magic number. ^__^ Am 04.03.2021 22:13:24 schrieb commits at source.squeak.org : Eliot Miranda uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-eem.1735.mcz ==================== Summary ==================== Name: Morphic-eem.1735 Author: eem Time: 4 March 2021, 1:13:03.650992 pm UUID: 7ba0bde5-351e-b94c-a4b5-a4846f3f907c Ancestors: Morphic-eem.1734 Use the constants on the class side of MouseEvent (adding numButtons to them) when creating the button field that (incredibly annoyingly) combines mouse buttons and modifier keys. This is a necessary first step to increasing the nu,ber of buttons to include the moveLeft and moveRight buttons on modern gaming mice. =============== Diff against Morphic-eem.1734 =============== Item was changed: ----- Method: HandMorph>>generateDropFilesEvent: (in category 'private events') ----- generateDropFilesEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer." | position buttons modifiers stamp numFiles dragType | stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Time eventMillisecondClock]. dragType := evtBuf third. position := evtBuf fourth @ evtBuf fifth. buttons := MouseEvent redButton. "hacked because necessary for correct mouseMoveDragging handling" modifiers := evtBuf sixth. + buttons := buttons bitOr: (modifiers bitShift: MouseEvent numButtons). - buttons := buttons bitOr: (modifiers bitShift: 3). numFiles := evtBuf seventh. dragType caseOf: { [1] -> [ "dragEnter" externalDropMorph := TransferMorph new dragTransferType: #filesAndDirectories; source: self; passenger: (numFiles = 0 "Usually, numFiles and drop paths are delivered on dragDrop only. Still reserving this possibility for able host implementations." ifTrue: [self flag: #vmCapabilityMissing. 'Unknown host content' translated] ifFalse: [FileDirectory dropFilesAndDirectories: numFiles]); yourself. "During the drag operation, the host system is responsible for displaying the cursor." self grabMorph: externalDropMorph. self showTemporaryCursor: Cursor blank. externalDropMorph bottomRight: self topLeft. "Southeast area of the cursor is blocked by drawings from the source application. Display our drop morph at the opposite corner of the cursor." ]. [2] -> [ "dragMove" ^ MouseMoveEvent new setType: #mouseMove startPoint: self position endPoint: position trail: "{self position. position}"(self mouseDragTrailFrom: evtBuf) buttons: buttons hand: self stamp: stamp ]. [3] -> [ "dragLeave" externalDropMorph ifNotNil: #abandon. externalDropMorph := nil. self showTemporaryCursor: nil ]. [4] -> [ "dragDrop" | oldButtons | externalDropMorph ifNil: [ "dragDrop has been sent without prior dragging. This happens when the VM is configured as singleton application and has been called again (aka #launchDrop)." ^ self error: 'Launch drop for singleton Squeak not yet implemented.']. self showTemporaryCursor: nil. externalDropMorph passenger isString ifTrue: [ self flag: #vmCapabilityMissing. "See above." externalDropMorph passenger: (FileDirectory dropFilesAndDirectories: numFiles)]. externalDropMorph := nil. (Smalltalk classNamed: #DropFilesEvent) ifNotNil: [:eventClass | | classicEvent | "Generate classic DropFilesEvent, providing backward compatibility." classicEvent := eventClass new setPosition: position contents: numFiles hand: self. self processEvent: classicEvent. classicEvent wasHandled ifTrue: [^ nil]]. oldButtons := lastEventBuffer fifth + bitOr: (lastEventBuffer sixth bitShift: MouseEvent numButtons). - bitOr: (lastEventBuffer sixth bitShift: 3). ^ MouseButtonEvent new setType: #mouseUp position: position which: (oldButtons bitXor: buttons) buttons: buttons nClicks: 0 hand: self stamp: stamp ]. [5] -> [ "drag request" "For dnd out. Not properly implemented at the moment." self shouldBeImplemented] }. ^ nil! Item was changed: ----- Method: HandMorph>>generateKeyboardEvent: (in category 'private events') ----- generateKeyboardEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer" | buttons modifiers type pressType stamp keyValue | stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Sensor eventTimeNow]. pressType := evtBuf fourth. pressType = EventKeyDown ifTrue: [type := #keyDown]. pressType = EventKeyUp ifTrue: [type := #keyUp]. pressType = EventKeyChar ifTrue: [type := #keystroke]. modifiers := evtBuf fifth. + buttons := (modifiers bitShift: MouseEvent numButtons) bitOr: (lastMouseEvent buttons bitAnd: MouseEvent anyButton). - buttons := (modifiers bitShift: 3) bitOr: (lastMouseEvent buttons bitAnd: 7). type = #keystroke ifTrue: [keyValue := (self keyboardInterpreter nextCharFrom: Sensor firstEvt: evtBuf) asInteger] ifFalse: [keyValue := evtBuf third]. ^ KeyboardEvent new setType: type buttons: buttons position: self position keyValue: keyValue hand: self stamp: stamp. ! Item was changed: ----- Method: HandMorph>>generateMouseEvent: (in category 'private events') ----- generateMouseEvent: evtBuf "Generate the appropriate mouse event for the given raw event buffer" | position buttons modifiers type trail stamp oldButtons evtChanged | evtBuf first = lastEventBuffer first ifTrue: ["Workaround for Mac VM bug, *always* generating 3 events on clicks" evtChanged := false. 3 to: evtBuf size do: [:i | (lastEventBuffer at: i) = (evtBuf at: i) ifFalse: [evtChanged := true]]. evtChanged ifFalse: [^nil]]. stamp := evtBuf second. stamp = 0 ifTrue: [stamp := Sensor eventTimeNow]. position := evtBuf third @ evtBuf fourth. buttons := evtBuf fifth. modifiers := evtBuf sixth. type := buttons = 0 + ifTrue: + [lastEventBuffer fifth = 0 + ifTrue: [#mouseMove] "this time no button and previously no button .. just mouse move" + ifFalse: [#mouseUp]] "this time no button but previously some button ... therefore button was released" + ifFalse: + [buttons = lastEventBuffer fifth + ifTrue: [#mouseMove] "button states are the same .. now and past .. therfore a mouse movement" + ifFalse: "button states are different .. button was pressed or released" + [buttons > lastEventBuffer fifth - ifTrue:[ - lastEventBuffer fifth = 0 - ifTrue: [#mouseMove] "this time no button and previously no button .. just mouse move" - ifFalse: [#mouseUp] "this time no button but previously some button ... therefore button was released" - ] - ifFalse:[ - buttons = lastEventBuffer fifth - ifTrue: [#mouseMove] "button states are the same .. now and past .. therfore a mouse movement" - ifFalse: [ "button states are different .. button was pressed or released" - buttons > lastEventBuffer fifth ifTrue: [#mouseDown] + ifFalse:[#mouseUp]]]. + buttons := buttons bitOr: (modifiers bitShift: MouseEvent numButtons). + oldButtons := lastEventBuffer fifth bitOr: (lastEventBuffer sixth bitShift: MouseEvent numButtons). - ifFalse:[#mouseUp]. - ]. - ]. - buttons := buttons bitOr: (modifiers bitShift: 3). - oldButtons := lastEventBuffer fifth - bitOr: (lastEventBuffer sixth bitShift: 3). lastEventBuffer := evtBuf. + type == #mouseMove ifTrue: + [trail := self mouseTrailFrom: evtBuf. + ^MouseMoveEvent new + setType: type + startPoint: self position + endPoint: trail last + trail: trail + buttons: buttons + hand: self + stamp: stamp]. - type == #mouseMove - ifTrue: - [trail := self mouseTrailFrom: evtBuf. - ^MouseMoveEvent new - setType: type - startPoint: (self position) - endPoint: trail last - trail: trail - buttons: buttons - hand: self - stamp: stamp]. ^MouseButtonEvent new setType: type position: position which: (oldButtons bitXor: buttons) buttons: buttons nClicks: (evtBuf seventh ifNil: [0]) hand: self stamp: stamp! Item was changed: ----- Method: HandMorph>>showEvent: (in category 'events-debugging') ----- showEvent: anEvent "Show details about the event on the display form. Useful for debugging." + "ShowEvents := true" + "ShowEvents := false" - | message borderWidth | ShowEvents == true ifFalse: [^ self]. borderWidth := 5. message := String streamContents: [:strm | strm nextPutAll: '[HandMorph >> #showEvent:]'; cr; nextPutAll: 'event'; tab; tab; tab; tab; nextPutAll: anEvent printString; cr; nextPutAll: 'keyboard focus'; tab; tab; nextPutAll: self keyboardFocus printString; cr; nextPutAll: 'mouse focus'; tab; tab; nextPutAll: self mouseFocus printString]. message := message asDisplayText foregroundColor: Color black backgroundColor: Color white. "Offset to support multiple hands debugging." Display fill: (0 @ 0 extent: message form extent + (borderWidth asPoint * 2)) rule: Form over fillColor: Color white. message displayOn: Display at: borderWidth asPoint + (0 @ ((owner hands indexOf: self) - 1 * message form height)).! Item was added: + ----- Method: MouseEvent class>>numButtons (in category 'constants') ----- + numButtons + "We support three button mice." + ^3! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 5 08:19:19 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 08:19:19 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1739.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1739.mcz ==================== Summary ==================== Name: Morphic-mt.1739 Author: mt Time: 5 March 2021, 9:19:14.941204 am UUID: 59a78e19-2616-5c4a-84e5-27a9e63d9c2e Ancestors: Morphic-eem.1738 Support source-code drops via method references such as from senders/implementors/message tools. =============== Diff against Morphic-eem.1738 =============== Item was changed: ----- Method: PasteUpMorph>>dropSourceCode:event: (in category 'event handling') ----- dropSourceCode: anObject event: evt + (anObject isMethodReference and: [anObject isValid]) + ifTrue: [^ self dropSourceCode: anObject compiledMethod event: evt]. + anObject isCompiledMethod ifTrue: [ | tool window | tool := CodeHolder new setClass: anObject methodClass selector: anObject selector. window := ToolBuilder open: tool. window center: evt position. window bounds: (window bounds translatedToBeWithin: self bounds)]. + - anObject isString ifTrue: [anObject edit].! From commits at source.squeak.org Fri Mar 5 08:21:20 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 08:21:20 0000 Subject: [squeak-dev] The Trunk: Tools-mt.1030.mcz Message-ID: Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1030.mcz ==================== Summary ==================== Name: Tools-mt.1030 Author: mt Time: 5 March 2021, 9:21:18.794204 am UUID: d7b63933-664e-b94e-af03-4b96f029b4e3 Ancestors: Tools-mt.1029 Fixes dragging in message-set tools (excluding MessageTrace, which needs drag to select multiple things). Tweaks label in CodeHolder to look like the labels in senders/implementors and all other message-set tools. =============== Diff against Tools-mt.1029 =============== Item was changed: ----- Method: CodeHolder>>labelString (in category 'initialize-release') ----- labelString + ^ currentCompiledMethod + ifNil: [self defaultBrowserTitle] + ifNotNil: [ + ('{1} {2} \{{3}\} \{{4}\}' format: { + self selectedClassOrMetaClass name. + self selectedMessageName. + self selectedMessageCategoryName. + self selectedSystemCategoryName })]! - | label | - label := self defaultBrowserTitle. - currentCompiledMethod ifNotNil: [ - label := label, (': {1} >> #{2} ({3})' format: { - self selectedClassOrMetaClass name. - self selectedMessageName. - self selectedMessageCategoryName })]. - ^ label! Item was changed: ----- Method: CodeHolder>>selectedMessageCategoryName (in category 'categories') ----- selectedMessageCategoryName "Answer the name of the message category of the message of the currently selected context." + ^ self selectedClassOrMetaClass organization categoryOfElement: self selectedMessageName! - ^ self selectedClass organization categoryOfElement: self selectedMessageName! Item was added: + ----- Method: CodeHolder>>selectedSystemCategoryName (in category 'categories') ----- + selectedSystemCategoryName + + ^ SystemOrganization categoryOfElement: self selectedClass name! Item was changed: ----- Method: MessageSet>>buildMessageListWith: (in category 'toolbuilder') ----- buildMessageListWith: builder | listSpec | listSpec := builder pluggableListSpec new. listSpec model: self; list: #messageListFormatted; getIndex: #messageListIndex; setIndex: #messageListIndex:; icon: #messageIconAt:; helpItem: #messageHelpAt:; menu: #messageListMenu:shifted:; keyPress: #messageListKey:from:. + SystemBrowser browseWithDragNDrop ifTrue: [ + listSpec + dragItem: #dragFromMessageList:; + dragType: #dragTypeForMessageListAt:]. + ^ listSpec - SystemBrowser browseWithDragNDrop - ifTrue:[listSpec dragItem: #dragFromMessageList:]. - ^listSpec ! Item was changed: ----- Method: MessageSet>>dragFromMessageList: (in category 'drag and drop') ----- dragFromMessageList: index + + ^ self messageList at: index! - "Drag a method from the browser" - ^self selectedClassOrMetaClass compiledMethodAt: (self messageList at: index) ifAbsent:[nil]! Item was removed: - ----- Method: MessageSet>>dragPassengerFor:inMorph: (in category 'drag and drop') ----- - dragPassengerFor: item inMorph: dragSource - | transferType | - transferType := self dragTransferTypeForMorph: dragSource. - transferType == #messageList - ifTrue: [^self selectedClassOrMetaClass->(item contents findTokens: ' ') second asSymbol]. - transferType == #classList - ifTrue: [^self selectedClass]. - ^nil! Item was added: + ----- Method: MessageSet>>dragTypeForMessageListAt: (in category 'drag and drop') ----- + dragTypeForMessageListAt: index + + ^ #sourceCode! From marcel.taeumel at hpi.de Fri Mar 5 08:23:11 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 09:23:11 +0100 Subject: [squeak-dev] The Trunk: Collections-nice.929.mcz In-Reply-To: References: Message-ID: Hi Nicolas, thank you for the quick response. :-) Best, Marcel Am 04.03.2021 18:55:18 schrieb commits at source.squeak.org : Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.929.mcz ==================== Summary ==================== Name: Collections-nice.929 Author: nice Time: 4 March 2021, 6:55:05.090663 pm UUID: 6e327843-eedc-4eeb-ba1b-0e14d4f40e56 Ancestors: Collections-nice.928 Don't hardcode Interval and LimitedPrecisionInterval so as to enable subclassing. Note: a subclass wanting to handle limited precision bounds or increment by itself should define: limitedPrecisionSpecies ^self. This is not the case of TextLineInterval that only ever see Integer bounds. =============== Diff against Collections-nice.928 =============== Item was changed: ----- Method: Interval class>>from:to: (in category 'instance creation') ----- from: startInteger to: stopInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of 1." ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision]) + ifTrue: [self limitedPrecisionSpecies] + ifFalse: [self]) basicNew - ifTrue: [LimitedPrecisionInterval] - ifFalse: [Interval]) basicNew setFrom: startInteger to: stopInteger by: 1! Item was changed: ----- Method: Interval class>>from:to:by: (in category 'instance creation') ----- from: startInteger to: stopInteger by: stepInteger "Answer an instance of me, starting at startNumber, ending at stopNumber, and with an interval increment of stepNumber." ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision or: [stepInteger hasLimitedPrecision]]) + ifTrue: [self limitedPrecisionSpecies] + ifFalse: [self]) basicNew - ifTrue: [LimitedPrecisionInterval] - ifFalse: [Interval]) basicNew setFrom: startInteger to: stopInteger by: stepInteger! Item was added: + ----- Method: Interval class>>limitedPrecisionSpecies (in category 'instance creation') ----- + limitedPrecisionSpecies + "Answer a class able to handle limited precision bounds or step" + + ^LimitedPrecisionInterval! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Fri Mar 5 08:25:17 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 09:25:17 +0100 Subject: [squeak-dev] The Trunk: Multilingual-eem.255.mcz In-Reply-To: References: Message-ID: +1 for moving MultiByteFileStream from "Multilingual" to "Files". Best, Marcel Am 04.03.2021 19:23:10 schrieb commits at source.squeak.org : Eliot Miranda uploaded a new version of Multilingual to project The Trunk: http://source.squeak.org/trunk/Multilingual-eem.255.mcz ==================== Summary ==================== Name: Multilingual-eem.255 Author: eem Time: 4 March 2021, 10:23:00.658047 am UUID: 55a1972b-10f3-4938-bc52-fa293e2b7973 Ancestors: Multilingual-ul.254 Cleanup related to Files-eem.187. BTW, seems to me that MultiByteFileStream no longer belongs in Multilingual, but would be better off in Files. =============== Diff against Multilingual-ul.254 =============== Item was changed: ----- Method: MultiByteFileStream>>requestDropStream: (in category 'private') ----- requestDropStream: dropIndex + "Override to install proper converter." - "Needs to install proper converter" + ^(super requestDropStream: dropIndex) ifNotNil: + [:result| - | result | - result := super requestDropStream: dropIndex. - result ifNotNil: [ converter ifNil: [self converter: UTF8TextConverter new]. + lineEndConvention ifNil: [ self detectLineEndConvention ]. + result]! - lineEndConvention ifNil: [ self detectLineEndConvention ] - ]. - ^result! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 5 08:30:09 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 08:30:09 0000 Subject: [squeak-dev] The Trunk: System-mt.1221.mcz Message-ID: Marcel Taeumel uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-mt.1221.mcz ==================== Summary ==================== Name: System-mt.1221 Author: mt Time: 5 March 2021, 9:30:06.646653 am UUID: faeeebfe-1564-e743-8e5a-8c26460ca3ad Ancestors: System-mt.1220, System-ct.1220 Merge. > Adds Jaromir Matas (jar) to the authors list. A late welcome aboard! :-) =============== Diff against System-mt.1220 =============== Item was changed: ----- Method: SystemNavigation class>>privateAuthorsRaw (in category 'class initialization') ----- (excessive size, no diff calculated) Item was changed: + (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors.......'! - (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors......'! From commits at source.squeak.org Fri Mar 5 08:30:32 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 08:30:32 0000 Subject: [squeak-dev] The Trunk: System-ct.1220.mcz Message-ID: Marcel Taeumel uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-ct.1220.mcz ==================== Summary ==================== Name: System-ct.1220 Author: ct Time: 2 March 2021, 2:06:08.80617 pm UUID: cf9872fd-fa5d-4bb6-bc1c-8ced48a02a48 Ancestors: System-mt.1219 Adds Jaromir Matas (jar) to the authors list. A late welcome aboard! :-) =============== Diff against System-mt.1219 =============== Item was changed: ----- Method: SystemNavigation class>>privateAuthorsRaw (in category 'class initialization') ----- (excessive size, no diff calculated) Item was changed: + (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors.......'! - (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors......'! From marcel.taeumel at hpi.de Fri Mar 5 08:35:14 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 09:35:14 +0100 Subject: [squeak-dev] The Trunk: Collections-nice.925.mcz In-Reply-To: References: Message-ID: Hi Nicolas. No worries. And the URL is behind the badge. Click on it and it will be copied to your clipboard: Best, Marcel Am 04.03.2021 18:55:51 schrieb Nicolas Cellier : Hi Marcel, yes sorry, I will fix it. I saw the red updateStream and failed to find the address of our CI. It should be more visible on squeak.org... Le jeu. 4 mars 2021 à 17:13, Marcel Taeumel a écrit : > > Hi all! > > This breaks subclassing for Interval. TextLineInterval is an example. Yet, it is used only in ST80, so I will change it there. > > What about #species? Or something similar? Do we really want to break subclassing on Interval? > > Best, > Marcel > > Am 03.03.2021 02:14:24 schrieb commits at source.squeak.org : > > Nicolas Cellier uploaded a new version of Collections to project The Trunk: > http://source.squeak.org/trunk/Collections-nice.925.mcz > > ==================== Summary ==================== > > Name: Collections-nice.925 > Author: nice > Time: 3 March 2021, 2:14:13.09562 am > UUID: ee92856e-98d1-3a41-a3f2-3529927e7a02 > Ancestors: Collections-jar.924 > > Distinguish questionable LimitedPrecisionInterval (those with Float bounds or step) from ordinary Interval of Integer, Fraction or ScaledDecimals. > > The main interest of having a specific class is to avoid crippling Interval with Float workarounds, for the rare use case. > > Explain some of the pitfalls of LimitedPrecisionInterval, and encourage alternatives in class comment, which is a second advantage of having a separate class. > > Abandon fuzzy inclusion logic, which is considered to introduce more discrepancies than it tries to solve > See http://bugs.squeak.org/view.php?id=6455. > and method #testSurprisingFuzzyInclusion > > Fix two other failing tests for Interval of Floats. > > Fix size so that (0.3 to: 1.2 by: 0.1) includes: 1.2. > See https://github.com/dolphinsmalltalk/Dolphin/issues/1108 > This makes size a bit less performant than super, a 3rd reason why a specific class is neat. > > Huh, that's more comments than code ;). > > =============== Diff against Collections-jar.924 =============== > > Item was changed: > ----- Method: Interval class>>from:to: (in category 'instance creation') ----- > from: startInteger to: stopInteger > "Answer an instance of me, starting at startNumber, ending at > stopNumber, and with an interval increment of 1." > > + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision]) > + ifTrue: [LimitedPrecisionInterval] > + ifFalse: [Interval]) basicNew > - ^self basicNew > setFrom: startInteger > to: stopInteger > by: 1! > > Item was changed: > ----- Method: Interval class>>from:to:by: (in category 'instance creation') ----- > from: startInteger to: stopInteger by: stepInteger > "Answer an instance of me, starting at startNumber, ending at > stopNumber, and with an interval increment of stepNumber." > > + ^((startInteger hasLimitedPrecision or: [stopInteger hasLimitedPrecision or: [stepInteger hasLimitedPrecision]]) > + ifTrue: [LimitedPrecisionInterval] > + ifFalse: [Interval]) basicNew > - ^self basicNew > setFrom: startInteger > to: stopInteger > by: stepInteger! > > Item was changed: > ----- Method: Interval>>indexOf:startingAt: (in category 'accessing') ----- > indexOf: anElement startingAt: startIndex > "startIndex is an positive integer, the collection index where the search is started." > - "during the computation of val , floats are only used when the receiver contains floats" > > + | index | > - | index val | > (self rangeIncludes: anElement) ifFalse: [ ^0 ]. > + index := (anElement - start / step) rounded + 1. > - val := anElement - self first / self increment. > - val isFloat > - ifTrue: [ > - (val - val rounded) abs * 100000000 < 1 ifFalse: [ ^0 ]. > - index := val rounded + 1 ] > - ifFalse: [ > - val isInteger ifFalse: [ ^0 ]. > - index := val + 1 ]. > - "finally, the value of startIndex comes into play:" > (index between: startIndex and: self size) ifFalse: [ ^0 ]. > + (self at: index) = anElement ifFalse: [ ^0 ]. > ^index! > > Item was added: > + Interval subclass: #LimitedPrecisionInterval > + instanceVariableNames: '' > + classVariableNames: '' > + poolDictionaries: '' > + category: 'Collections-Sequenceable'! > + > + !LimitedPrecisionInterval commentStamp: 'nice 3/3/2021 01:47' prior: 0! > + A LimitedPrecisionInterval is an Interval whose bounds or step haveLimitedPrecision. > + Due to inexact arithmetic, special precautions must be taken in the implementation, > + in order to avoid unconsistent and surprising behavior as much as possible. > + > + Despite those efforts, LimitedPrecisionInterval is full of pitfalls. > + It is recommended to avoid using LimitedPrecisionInterval unless understanding those pitfalls. > + For example, (0.2 to: 0.6 by: 0.1) last = 0.5. > + This interval does not includes 0.6 because (0.1*4+0.2) is slightly greater than 0.6. > + Another example is that (0.2 to: 0.6 by: 0.1) does not include 0.3 but a Float slightly greater. > + > + A usual workaround is to use an Integer interval, and reconstruct the Float inside the loop. > + For example: > + (0 to: 4) collect: [:i | 0.1*i+0.2]. > + or better if we want to have 0.3 and 0.6: > + (2 to: 6) collect: [:i | i / 10.0]. > + Another workaround is to not use limited precision at all, but Fraction or ScaledDecimal when possible: > + (1/10 to: 7/10 by: 1/10). > + (0.1s to: 0.7s by: 0.1s). > + > + Yet another pitfall is that optimized to:by:do: might differ from (to:by:) do: > + In the former case, repeated addition of increment is used, in the later, a multiplication is used. > + Observe the differences: > + Array streamContents: [:str | 0 to: 3 by: 0.3 do: [:e | str nextPut: e]]. > + Array streamContents: [:str | (0 to: 3 by: 0.3) do: [:e | str nextPut: e]]. > + > + There are many more discrepancies, so use carefully, or not use it at all.! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>copyFrom:to: (in category 'copying') ----- > + copyFrom: startIndex to: stopIndex > + startIndex = 1 ifTrue: [^super copyFrom: startIndex to: stopIndex]. > + stopIndex < startIndex ifTrue: [^self copyEmpty]. > + ^Array new: stopIndex - startIndex + 1 streamContents: [:stream | > + startIndex to: stopIndex do: [:i | stream nextPut: (self at: i)]]! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>last (in category 'accessing') ----- > + last > + "Refer to the comment in SequenceableCollection|last." > + > + ^start + (step * (self size - 1))! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>reversed (in category 'converting') ----- > + reversed > + "There is no guaranty that super reversed would contain same elements. > + Answer an Array instead" > + > + ^Array new: self size streamContents: [:stream | self reverseDo: [:each | stream nextPut: each]]! > > Item was added: > + ----- Method: LimitedPrecisionInterval>>size (in category 'accessing') ----- > + size > + "Answer how many elements the receiver contains." > + > + | candidateSize | > + candidateSize := (stop - start / step max: 0) rounded. > + step > 0 > + ifTrue: [candidateSize * step + start <= stop ifTrue: [^candidateSize + 1]] > + ifFalse: [candidateSize * step + start >= stop ifTrue: [^candidateSize + 1]]. > + ^candidateSize! > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 37114 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 21570 bytes Desc: not available URL: From m at jaromir.net Fri Mar 5 08:56:25 2021 From: m at jaromir.net (Jaromir Matas) Date: Fri, 5 Mar 2021 02:56:25 -0600 (CST) Subject: [squeak-dev] #valueNoContextSwitch no different from #value? Message-ID: <1614934585919-0.post@n4.nabble.com> Hi, I tried to test how #valueNoContextSwitch behavior differs from #value. I created a victim process p and an intruder process q trying to attack where the difference between #valueNoContextSwitch and #value should lie: between the #value send and the first context switching point inside the block, i.e. between points (A) and (B) here: process p (victim): [ x := nil. "(A)" [x "(B)" ifNotNil: ["report intrusion"]] value ] "repeat many times" process q (intruder, higher priority) [x := 1. "wait a bit"] "repeat" The #value send is a context switching point too but it's the only one between A and B in case of #valueNoContextSwitch. So if there were more switching points inside #value we should see a difference. Unfortunately, I couldn't see any difference and would really appreaciate your advice where I am wrong. Here's the whole testing set (outer fork for shielding from UI): [ | p q x val sema log cycle attempts | x := val := nil. attempts := 0. cycle := 0. sema := Semaphore new. log := {} writeStream. p := [sema wait. [x := nil. [val := x. val ifNotNil: [log nextPut: cycle]] valueNoContextSwitch. cycle := cycle + 1. cycle < 100000000] whileTrue. Transcript cr; show: 'intrusions: ', log contents size] forkAt: 42. q := [sema signal. [x := 1. attempts := attempts + 1. 3 milliSeconds wait. p isTerminated] whileFalse. Transcript show: ' out of ', attempts, ' attempts in ', cycle, ' cycles'] forkAt: 43. ] forkAt: 41 The results in both cases are almost identical: value: intrusions: 178 out of 331 attempts in 100000000 cycles intrusions: 189 out of 324 attempts in 100000000 cycles valueNoContextSwitch: intrusions: 194 out of 338 attempts in 100000000 cycles intrusions: 191 out of 328 attempts in 100000000 cycles As a side-effect I verified a faulty behavior of #valueUnpreemptively I reported here: http://forum.world.st/The-Inbox-Kernel-jar-1368-mcz-tp5126894p5126897.html #valueUnpreemptively returns e.g. the following: intrusions: 0 out of 2 attempts in 100000000 cycles intrusions: 3 out of 6 attempts in 100000000 cycles This shows the process p runs at priority 80 even after #valueUnpreemptively ended and p returned to its previous lower than q priority. As a result q almost never gets a chance to execute even if it has a higher priority than p most of the time. In addition, when I tried to apply the fix I suggested in http://forum.world.st/The-Inbox-Kernel-jar-1368-mcz-tp5126894p5126897.html , the performance deteriorated so badly that I'm going to recall my suggestion (the only reasonable solution to fix the priority issue is a new primitive). Any suggestion regarding #valueNoContextSwitch test and where my design is wrong would be greatly appreciated. Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Fri Mar 5 09:27:58 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 10:27:58 +0100 Subject: [squeak-dev] #valueNoContextSwitch no different from #value? In-Reply-To: <1614934585919-0.post@n4.nabble.com> References: <1614934585919-0.post@n4.nabble.com> Message-ID: Hi Jaromir. Wow! That's a thorough experiment. :-) Maybe also add your current conclusions to that other thread: http://forum.world.st/The-Inbox-Kernel-jar-1368-mcz-tp5126894p5126897.html Best, Marcel Am 05.03.2021 09:56:35 schrieb Jaromir Matas : Hi, I tried to test how #valueNoContextSwitch behavior differs from #value. I created a victim process p and an intruder process q trying to attack where the difference between #valueNoContextSwitch and #value should lie: between the #value send and the first context switching point inside the block, i.e. between points (A) and (B) here: process p (victim): [ x := nil. "(A)" [x "(B)" ifNotNil: ["report intrusion"]] value ] "repeat many times" process q (intruder, higher priority) [x := 1. "wait a bit"] "repeat" The #value send is a context switching point too but it's the only one between A and B in case of #valueNoContextSwitch. So if there were more switching points inside #value we should see a difference. Unfortunately, I couldn't see any difference and would really appreaciate your advice where I am wrong. Here's the whole testing set (outer fork for shielding from UI): [ | p q x val sema log cycle attempts | x := val := nil. attempts := 0. cycle := 0. sema := Semaphore new. log := {} writeStream. p := [sema wait. [x := nil. [val := x. val ifNotNil: [log nextPut: cycle]] valueNoContextSwitch. cycle := cycle + 1. cycle Transcript cr; show: 'intrusions: ', log contents size] forkAt: 42. q := [sema signal. [x := 1. attempts := attempts + 1. 3 milliSeconds wait. p isTerminated] whileFalse. Transcript show: ' out of ', attempts, ' attempts in ', cycle, ' cycles'] forkAt: 43. ] forkAt: 41 The results in both cases are almost identical: value: intrusions: 178 out of 331 attempts in 100000000 cycles intrusions: 189 out of 324 attempts in 100000000 cycles valueNoContextSwitch: intrusions: 194 out of 338 attempts in 100000000 cycles intrusions: 191 out of 328 attempts in 100000000 cycles As a side-effect I verified a faulty behavior of #valueUnpreemptively I reported here: http://forum.world.st/The-Inbox-Kernel-jar-1368-mcz-tp5126894p5126897.html #valueUnpreemptively returns e.g. the following: intrusions: 0 out of 2 attempts in 100000000 cycles intrusions: 3 out of 6 attempts in 100000000 cycles This shows the process p runs at priority 80 even after #valueUnpreemptively ended and p returned to its previous lower than q priority. As a result q almost never gets a chance to execute even if it has a higher priority than p most of the time. In addition, when I tried to apply the fix I suggested in http://forum.world.st/The-Inbox-Kernel-jar-1368-mcz-tp5126894p5126897.html , the performance deteriorated so badly that I'm going to recall my suggestion (the only reasonable solution to fix the priority issue is a new primitive). Any suggestion regarding #valueNoContextSwitch test and where my design is wrong would be greatly appreciated. Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Fri Mar 5 10:22:04 2021 From: m at jaromir.net (Jaromir Matas) Date: Fri, 5 Mar 2021 04:22:04 -0600 (CST) Subject: [squeak-dev] #valueNoContextSwitch no different from #value? In-Reply-To: References: <1614934585919-0.post@n4.nabble.com> Message-ID: <1614939724054-0.post@n4.nabble.com> I'm just working on it :D Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Fri Mar 5 10:31:15 2021 From: m at jaromir.net (Jaromir Matas) Date: Fri, 5 Mar 2021 04:31:15 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1368.mcz In-Reply-To: References: <1612981853325-0.post@n4.nabble.com> <1612985231265-0.post@n4.nabble.com> Message-ID: <1614940275655-0.post@n4.nabble.com> In http://forum.world.st/valueNoContextSwitch-no-different-from-value-td5127491.html I tested #valueNoContextSwitch and accidentally verified again how badly broken #valueUnpreemptively is due to the #priority bug. I also tried to apply the workaround I suggested in this post ([] forkAt: Processor highestPriority) and it's desperately slow so I can only agree a new primitive is probably the only good solution. I dont't think we necessarily need a whole #priority as a primitive though. A primitive where the scheduler gives an active process a kick to *preempt* when downgrading its priority should suffice: Process>>priority: anInteger self isActiveProcess ifTrue: [primitivePriority: anInteger] ... (so it's not the same as yielding; it's like preempting: take #valueUnpreemptively as an example - a process raises its priority and later goes back where it was - I guess the desired behavior is the process continues running after the downgrade (and no more higher prio processes present) even if there are processes waiting at the lower priority; they may have there even before the process raised its priority, so why send it to the back :) . I guess this Kernel-jar.1368.mcz can be removed from The Inbox. regards, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Fri Mar 5 12:55:45 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 13:55:45 +0100 Subject: [squeak-dev] Squeak Winter Demos, 2021/03/06, 3 p.m. - 6 p.m. CET, virtual In-Reply-To: References: Message-ID: Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! Here are the information for the upcoming "Squeak Winter Demos", which you can also read about on https://squeak.de/news/ [https://squeak.de/news/]. The login for the meeting is as follows: Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) https://uni-potsdam.zoom.us/j/61595939773 [https://uni-potsdam.zoom.us/j/61595939773] Meeting ID: 615 9593 9773 Passcode: 10202428 If you have anymore questions, feel free to contact me under marcel.taeumel at hpi.de [mailto:marcel.taeumel at hpi.de]. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: info at squeak-ev.de [mailto:info at squeak-ev.de] Internet: http://www.squeak.de/squeakev [http://www.squeak.de/squeakev] Am 09.02.2021 17:43:52 schrieb Marcel Taeumel : Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! We hope that you are doing well in these difficult times. Please take care of yourself and your peers. We cordially invite you to the “Squeak Winter Demos”, which are organized by the club of German-speaking Squeakers (“Squeak Deutschland e.V.”). We are going to fill that meeting with exciting talks, demos, and discussions. You want to attend or have more questions? Maybe even a proposal for a demo/talk/discussion? Feel free to talk to us so that we can better include your idea in the schedule. Since we want to keep the meeting as flexible as possible, every speaker should plan for about 20 minutes. When? Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) Where? The event will take place as a Zoom call. You need a webcam (maybe with a microphone) and a recent Web browser such as Firefox, Chrome, Edge, or Safari. Alternatively, you can download an app for your operating system via https://zoom.us/download [https://zoom.us/download]. We will share the login data for the virtual meeting here on the day of the event. What will happen? We are currently in the process of planning talks and demos. Feel free to contribute with a short demo or experience report yourself – even on the fly if you want to! We welcome non-members to the meeting. :) Here is a preliminary agenda: * Like the Babylonias: Programming with Examples * Fast and colorful: OpenGL in Squeak * Use the Entire Canvas: Block-based Programming * Spot off, Morph on: Squeak Game Showcase 2020 * It’s Broken! How to debug the debugger =) * Social Media? A Telegram Bot for Squeak … and those who find the time but are not so fluent in German: We always welcome non-German-speaking Squeakers, too! We suppose that you will understand the live demonstrations anyway. :) We will be able to translate technical details or questions into English as well. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: info at squeak-ev.de [mailto:info at squeak-ev.de] Internet: http://www.squeak.de/squeakev [http://www.squeak.de/squeakev] -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Fri Mar 5 15:09:30 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Fri, 5 Mar 2021 10:09:30 -0500 Subject: [squeak-dev] smalltalkCI is broken for Trunk In-Reply-To: References: Message-ID: <20210305150930.GA13690@shell.msen.com> On Thu, Mar 04, 2021 at 04:20:59PM +0100, Marcel Taeumel wrote: > I made an educated guess and restored "update-nice.469.mcm" to this: > Note that you can now add a comment to the MCM to explain what you are doing when modifying an existing MCM. To give an idea of how this works, you can browse update-nice.469 and click the Versions button on the upper right to open an explorer on the versions, see attached. Note also that the MCM files have a simple format, so you can save them to a local repository and do anything you like to them without actually affecting the source.squeak.org repository. This is handy if you need to do some experimenting or just test to see how it works. Dave -------------- next part -------------- A non-text attachment was scrubbed... Name: MCConfiguration-update-nice.469-Versions.png Type: image/png Size: 50593 bytes Desc: not available URL: From leves at caesar.elte.hu Fri Mar 5 16:28:55 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Fri, 5 Mar 2021 17:28:55 +0100 (CET) Subject: [squeak-dev] The Trunk: Multilingual-eem.255.mcz In-Reply-To: References: Message-ID: MultiByteFileStream has a non-file-based sibling: MultiByteBinaryOrTextStream. It could use some love to be on par with MultiByteFileStream feature-wise, but I didn't do that hoping that by now both would be obsolete and replaced with a composable stream implementation. Levente On Fri, 5 Mar 2021, Marcel Taeumel wrote: > +1 for moving MultiByteFileStream from "Multilingual" to "Files". > Best, > Marcel > > Am 04.03.2021 19:23:10 schrieb commits at source.squeak.org : > > Eliot Miranda uploaded a new version of Multilingual to project The Trunk: > http://source.squeak.org/trunk/Multilingual-eem.255.mcz > > ==================== Summary ==================== > > Name: Multilingual-eem.255 > Author: eem > Time: 4 March 2021, 10:23:00.658047 am > UUID: 55a1972b-10f3-4938-bc52-fa293e2b7973 > Ancestors: Multilingual-ul.254 > > Cleanup related to Files-eem.187. > > BTW, seems to me that MultiByteFileStream no longer belongs in Multilingual, but would be better off in Files. > > =============== Diff against Multilingual-ul.254 =============== > > Item was changed: > ----- Method: MultiByteFileStream>>requestDropStream: (in category 'private') ----- > requestDropStream: dropIndex > + "Override to install proper converter." > - "Needs to install proper converter" > > + ^(super requestDropStream: dropIndex) ifNotNil: > + [:result| > - | result | > - result := super requestDropStream: dropIndex. > - result ifNotNil: [ > converter ifNil: [self converter: UTF8TextConverter new]. > + lineEndConvention ifNil: [ self detectLineEndConvention ]. > + result]! > - lineEndConvention ifNil: [ self detectLineEndConvention ] > - ]. > - ^result! > > > > From marcel.taeumel at hpi.de Fri Mar 5 17:49:28 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 5 Mar 2021 18:49:28 +0100 Subject: [squeak-dev] smalltalkCI is broken for Trunk In-Reply-To: <20210305150930.GA13690@shell.msen.com> References: <20210305150930.GA13690@shell.msen.com> Message-ID: Hi Dave, thanks for the tip :-) How is the list of versions computed? Seems to be rather empty in my image. Only 483 and 482 are connected. Best, Marcel Am 05.03.2021 16:09:42 schrieb David T. Lewis : On Thu, Mar 04, 2021 at 04:20:59PM +0100, Marcel Taeumel wrote: > I made an educated guess and restored "update-nice.469.mcm" to this: > Note that you can now add a comment to the MCM to explain what you are doing when modifying an existing MCM. To give an idea of how this works, you can browse update-nice.469 and click the Versions button on the upper right to open an explorer on the versions, see attached. Note also that the MCM files have a simple format, so you can save them to a local repository and do anything you like to them without actually affecting the source.squeak.org repository. This is handy if you need to do some experimenting or just test to see how it works. Dave -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Fri Mar 5 18:37:12 2021 From: m at jaromir.net (Jaromir Matas) Date: Fri, 5 Mar 2021 12:37:12 -0600 (CST) Subject: [squeak-dev] Explorer / Inspector bug? Message-ID: <1614969432339-0.post@n4.nabble.com> Hi, I tried to explore and debug this simple code: p := [[true] whileTrue: [10 second wait]] fork p explore ... the explorer shows pc=nil and sender=nil but the process is running and responding correctly to isTerminated test and also showing correct answers in the bottom mini-workspace. However, when I open another explorer on the suspendedContext, it shows pc=nil and sender=nil even in the miniworkspace... This doesn't seem right but can't figure out where the problem is. And the explorer has to be run as a separate command... ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From tim at rowledge.org Fri Mar 5 18:44:45 2021 From: tim at rowledge.org (tim Rowledge) Date: Fri, 5 Mar 2021 10:44:45 -0800 Subject: [squeak-dev] The Trunk: Kernel-eem.1378.mcz In-Reply-To: References: Message-ID: > On 2021-03-04, at 11:50 PM, Marcel Taeumel wrote: > > Note that, at some point, we might want to move both EventSensor and event classes (e.g. MouseEvent) into a common package. Because leaving it like this would make Kernel depending on Morphic. :-) A very, very, long time ago Andreas & I had Words about this matter. When I first wrote the event sensor stuff I left it as very Morphic related, which seemed reasonable at the time for a prototype. Andreas correctly, albeit rudely, pointed out that the basic mechanism should not tie to Morphic or indeed any other specific UI layer. I think we eventually worked that part out ok. One might argue that EventSensor and a few other classes should be moved into a category other than Kernel-Processes on grounds of not being really wanted for some postulated totally headless image. Thinking about this reminds me that it might be a good idea to merge in the keyboard state tracking that I made for NuScratch. Internalised into EventSensor might simplify it; and perhaps it is a good model for replacing the messy #peekButtons etc. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim The subjunctive would have walked into a bar, had it only known. From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 5 18:49:46 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 5 Mar 2021 18:49:46 +0000 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <1614969432339-0.post@n4.nabble.com> References: <1614969432339-0.post@n4.nabble.com> Message-ID: Hi Jaromir, from what I know the VM initializes Context objects lazily and only to the required extent. Eliot wrote an interesting "marriage story" about this recently, see: http://forum.world.st/Two-new-curious-Context-primitive-questions-tp5125779p5125782.html Also, suspendedContext is only set when the process is not running at the moment. Did you try to fetch the same values from the process itself by using "thisContext"? Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Freitag, 5. März 2021 19:37:12 An: squeak-dev at lists.squeakfoundation.org Betreff: [squeak-dev] Explorer / Inspector bug? Hi, I tried to explore and debug this simple code: p := [[true] whileTrue: [10 second wait]] fork p explore ... the explorer shows pc=nil and sender=nil but the process is running and responding correctly to isTerminated test and also showing correct answers in the bottom mini-workspace. However, when I open another explorer on the suspendedContext, it shows pc=nil and sender=nil even in the miniworkspace... This doesn't seem right but can't figure out where the problem is. And the explorer has to be run as a separate command... ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Patrick.Rein at hpi.de Fri Mar 5 19:12:11 2021 From: Patrick.Rein at hpi.de (Rein, Patrick) Date: Fri, 5 Mar 2021 19:12:11 +0000 Subject: [squeak-dev] Bag>>#rehash missing Message-ID: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> Hi everyone, during a recent debugging session I noticed that Bag does not implement #rehash although it is, in essence, a hash-based collection and should therefore probably roughly adhere to the protocol of HashedCollection. Is there a good reason not to have #rehash on Bag? On a similar note: HashedCollection>>#rehash is in the `private` protocol but has various senders. As even the class comment mentions the usage of #rehash, I would also propose to move it out of the `private` protocol. :) Best wishes, Patrick From lewis at mail.msen.com Fri Mar 5 19:18:21 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Fri, 5 Mar 2021 14:18:21 -0500 Subject: [squeak-dev] smalltalkCI is broken for Trunk In-Reply-To: References: <20210305150930.GA13690@shell.msen.com> Message-ID: <20210305191821.GA60225@shell.msen.com> Hi Marcel, On Fri, Mar 05, 2021 at 06:49:28PM +0100, Marcel Taeumel wrote: > Hi Dave, > > thanks for the tip :-) How is the list of versions computed? Seems to be rather empty in my image. Only 483 and 482 are connected. It is done in MCConfigurationExtended, see #contentsOn:keyPrefix: to see how it is saved. It basically just acts like a list of prior configurations, saved in such a way that it is backward compatible with the original MCConfiguration storage format. Test coverage is in MCConfigurationTest, see category 'tests - extended format'. This was added to trunk a while back, but only recently installed on the source.squeak.org server. You may be the first person to have done such an update there. Dave > > Best, > Marcel > Am 05.03.2021 16:09:42 schrieb David T. Lewis : > On Thu, Mar 04, 2021 at 04:20:59PM +0100, Marcel Taeumel wrote: > > I made an educated guess and restored "update-nice.469.mcm" to this: > > > > Note that you can now add a comment to the MCM to explain what you are > doing when modifying an existing MCM. > > To give an idea of how this works, you can browse update-nice.469 and > click the Versions button on the upper right to open an explorer on > the versions, see attached. > > Note also that the MCM files have a simple format, so you can save > them to a local repository and do anything you like to them without > actually affecting the source.squeak.org repository. This is handy > if you need to do some experimenting or just test to see how it works. > > Dave > > > From lewis at mail.msen.com Fri Mar 5 21:43:09 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Fri, 5 Mar 2021 16:43:09 -0500 Subject: [squeak-dev] smalltalkCI is broken for Trunk In-Reply-To: <20210305191821.GA60225@shell.msen.com> References: <20210305150930.GA13690@shell.msen.com> <20210305191821.GA60225@shell.msen.com> Message-ID: <20210305214309.GA83130@shell.msen.com> On Fri, Mar 05, 2021 at 02:18:21PM -0500, David T. Lewis wrote: > Hi Marcel, > > On Fri, Mar 05, 2021 at 06:49:28PM +0100, Marcel Taeumel wrote: > > Hi Dave, > > > > thanks for the tip :-) How is the list of versions computed? Seems to be rather empty in my image. Only 483 and 482 are connected. > > It is done in MCConfigurationExtended, see #contentsOn:keyPrefix: to see > how it is saved. It basically just acts like a list of prior configurations, > saved in such a way that it is backward compatible with the original > MCConfiguration storage format. Test coverage is in MCConfigurationTest, > see category 'tests - extended format'. > > This was added to trunk a while back, but only recently installed on > the source.squeak.org server. You may be the first person to have > done such an update there. > Actually now that I think about it, I have a copy of the update-nice.469 map as of 09-Aug-2020 saved in the version history of update.V3-dtl.469 over in the update stream for www.squeaksource.com/TrunkUpdateStreamV3. Attaching update.V3-dtl.469.mcm for reference, along with update-nice.469-saved-in-an-MCM-version.png to show an explorer on the history. With that in mind, it is easy to edit the update.V3-dtl.469.mcm file to recreate the original update-nice.469.mcm as it was in August. The edited file is attached as update-nice.469.mcm. Dave > > > > > > Best, > > Marcel > > Am 05.03.2021 16:09:42 schrieb David T. Lewis : > > On Thu, Mar 04, 2021 at 04:20:59PM +0100, Marcel Taeumel wrote: > > > I made an educated guess and restored "update-nice.469.mcm" to this: > > > > > > > Note that you can now add a comment to the MCM to explain what you are > > doing when modifying an existing MCM. > > > > To give an idea of how this works, you can browse update-nice.469 and > > click the Versions button on the upper right to open an explorer on > > the versions, see attached. > > > > Note also that the MCM files have a simple format, so you can save > > them to a local repository and do anything you like to them without > > actually affecting the source.squeak.org repository. This is handy > > if you need to do some experimenting or just test to see how it works. > > > > Dave > > > > > > > > > -------------- next part -------------- A non-text attachment was scrubbed... Name: update.V3-dtl.469.mcm Type: chemical/x-macmolecule Size: 15147 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: update-nice.469-saved-in-an-MCM-version.png Type: image/png Size: 76811 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: update-nice.469.mcm Type: chemical/x-macmolecule Size: 7416 bytes Desc: not available URL: From m at jaromir.net Fri Mar 5 23:07:39 2021 From: m at jaromir.net (Jaromir Matas) Date: Fri, 5 Mar 2021 17:07:39 -0600 (CST) Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1614969432339-0.post@n4.nabble.com> Message-ID: <1614985659729-0.post@n4.nabble.com> Hi Christoph, thanks for the link - it's a brilliant summary of the long detailed version mentioned inside! Many thanks, Eliot! Here's my mistake: I setup a `10 second wait` instead of `10 second*s* wait` and Squeak interprets this typo as 1 second wait so I was watching a history only - sorry for the noise :) best, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Fri Mar 5 23:35:34 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 5 Mar 2021 23:35:34 0000 Subject: [squeak-dev] The Inbox: SUnit-ct.132.mcz Message-ID: A new version of SUnit was added to project The Inbox: http://source.squeak.org/inbox/SUnit-ct.132.mcz ==================== Summary ==================== Name: SUnit-ct.132 Author: ct Time: 6 March 2021, 12:35:33.710439 am UUID: 98d667df-13be-d148-9117-0b214c9adb3f Ancestors: SUnit-nice.124 Refactors and completes equality assertions - Add #deny:equals:description:, #deny:identical:, and #deny:identical:description: - Revise default description message for #deny:equals:, aligning it to #assert:equals: description - Make equality assertions capable of lazy descriptions (aStringOrBlock), aligning them to #assert:description: etc. - Add multilingual support for default description messages - Some internal refactoring - Improve test coverage of these assertions in SUnitTest Thanks to Marcel for pointing to the idea! Uploaded again to resolve conflicts with SUnit-pre.122 (recategorization). Replaces SUnit-ct.126 which can be moved into the treated inbox. :-) =============== Diff against SUnit-nice.124 =============== Item was added: + ----- Method: SUnitTest>>testAssertEquals (in category 'tests') ----- + testAssertEquals + + | a b | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self assert: a equals: a copy] raise: TestFailure. + + self should: [self assert: a equals: b] raise: TestFailure. + + [self assert: a equals: b] + on: TestFailure do: [:ex | + | error | + error := ex messageText. + self + assert: (error includesSubstring: a) + description: 'Error message doesn''t include the expected value'. + self + assert: (error includesSubstring: b) + description: 'Error message doesn''t include the actual value'].! Item was added: + ----- Method: SUnitTest>>testAssertEqualsDescription (in category 'tests') ----- + testAssertEqualsDescription + + | a b called | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self assert: a equals: a copy description: 'A description42'] raise: TestFailure. + + self should: [self assert: a equals: b description: 'A description42'] raise: TestFailure. + + [self assert: a equals: b description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self assert: a equals: a description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self assert: a equals: b description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! Item was changed: ----- Method: SUnitTest>>testAssertIdentical (in category 'tests') ----- testAssertIdentical + | a b | a := 'foo'. b := 'bar'. + + self shouldnt: [self assert: a identical: a] raise: TestFailure. + self should: [self assert: a identical: b] raise: TestFailure. + + [self assert: a identical: b] + on: TestFailure do: [:ex | + | error | + error := ex messageText. + self + assert: (error includesSubstring: a) + description: 'Error message doesn''t include the expected value'. + self + assert: (error includesSubstring: b) + description: 'Error message doesn''t include the actual value'].! - [self assert: a identical: b] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: a) description: 'Error message doesn''t include the expected value'. - self assert: (error includesSubstring: b) description: 'Error message doesn''t include the expected value'].! Item was changed: ----- Method: SUnitTest>>testAssertIdenticalDescription (in category 'tests') ----- testAssertIdenticalDescription + + | a b called | - | a b | a := 'foo'. b := a copy. + + self shouldnt: [self assert: a identical: a description: 'A description42'] raise: TestFailure. + + self should: [self assert: a identical: b description: 'A description42'] raise: TestFailure. + + [self assert: a identical: b description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self assert: a identical: a description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self assert: a identical: b description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! - self should: [self assert: a identical: b description: 'A desciption'] raise: TestFailure. - [self assert: a identical: b description: 'A desciption'] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: 'A desciption') description: 'Error message doesn''t give you the description'].! Item was changed: ----- Method: SUnitTest>>testAssertIdenticalWithEqualObjects (in category 'tests') ----- testAssertIdenticalWithEqualObjects + | a b | a := 'foo'. b := a copy. + self should: [self assert: a identical: b] raise: TestFailure. + + [self assert: a identical: b] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'not identical') + description: 'Error message doesn''t say the two things aren''t identical'].! - [self assert: a identical: b] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: 'not identical') description: 'Error message doesn''t say the two things aren''t identical'].! Item was added: + ----- Method: SUnitTest>>testDenyEquals (in category 'tests') ----- + testDenyEquals + + | a b | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self deny: a equals: b] raise: TestFailure. + + self should: [self deny: a equals: a copy] raise: TestFailure. + + [self deny: a equals: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: a) + description: 'Error message doesn''t include the unexpected value'].! Item was added: + ----- Method: SUnitTest>>testDenyEqualsDescription (in category 'tests') ----- + testDenyEqualsDescription + + | a b called | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self deny: a equals: b description: 'A description42'] raise: TestFailure. + + self should: [self deny: a equals: a copy description: 'A description42'] raise: TestFailure. + + [self deny: a equals: a description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self deny: a equals: b description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self deny: a equals: a description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! Item was added: + ----- Method: SUnitTest>>testDenyIdentical (in category 'tests') ----- + testDenyIdentical + + | a b | + a := 'foo'. + b := 'bar'. + self shouldnt: [self deny: a identical: b] raise: TestFailure. + self should: [self deny: a identical: a] raise: TestFailure. + [self deny: a identical: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: a) + description: 'Error message doesn''t include the unexpected value'].! Item was added: + ----- Method: SUnitTest>>testDenyIdenticalDescription (in category 'tests') ----- + testDenyIdenticalDescription + + | a b called | + a := 'foo'. + b := a copy. + + self shouldnt: [self deny: a identical: b description: 'A description42'] raise: TestFailure. + + self should: [self deny: a identical: a description: 'A description42'] raise: TestFailure. + + [self deny: a identical: a description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self deny: a identical: b description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self deny: a identical: a description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the description'].! Item was added: + ----- Method: SUnitTest>>testDenyIdenticalWithEqualObjects (in category 'tests') ----- + testDenyIdenticalWithEqualObjects + + | a b | + a := 'foo'. + b := a copy. + self should: [self deny: a identical: a] raise: TestFailure. + [self deny: a identical: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'identical') + description: 'Error message doesn''t say the two things are identical'].! Item was changed: ----- Method: TestCase>>assert:equals: (in category 'asserting') ----- assert: expected equals: actual + ^ self + assert: expected + equals: actual + description: nil - ^self - assert: expected = actual - description: [ self comparingStringBetween: expected and: actual ] ! Item was changed: ----- Method: TestCase>>assert:equals:description: (in category 'asserting') ----- + assert: expected equals: actual description: aStringOrBlock - assert: expected equals: actual description: aString + ^ self - ^self assert: expected = actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetween: expected and: actual)]! - description: [ aString , ': ', (self comparingStringBetween: expected and: actual) ]! Item was changed: ----- Method: TestCase>>assert:identical: (in category 'asserting') ----- assert: expected identical: actual + ^ self + assert: expected + identical: actual + description: nil! - ^self - assert: expected == actual - description: [ self comparingStringBetweenIdentical: expected and: actual ] - ! Item was changed: ----- Method: TestCase>>assert:identical:description: (in category 'asserting') ----- + assert: expected identical: actual description: aStringOrBlock - assert: expected identical: actual description: aString + ^ self - ^self assert: expected == actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetween: expected andIdentical: actual)]! - description: [ aString , ': ', (self comparingStringBetweenIdentical: expected and: actual) ]! Item was changed: ----- Method: TestCase>>comparingStringBetween:and: (in category 'private') ----- comparingStringBetween: expected and: actual + + ^ 'Expected {1} but was {2}.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! - ^ String streamContents: [:stream | - stream - nextPutAll: 'Expected '; - nextPutAll: (expected printStringLimitedTo: 10); - nextPutAll: ' but was '; - nextPutAll: (actual printStringLimitedTo: 10); - nextPutAll: '.' - ]! Item was added: + ----- Method: TestCase>>comparingStringBetween:andIdentical: (in category 'private') ----- + comparingStringBetween: expected andIdentical: actual + + ^ 'Expected {1} and actual {2} are not identical.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was changed: ----- Method: TestCase>>comparingStringBetweenIdentical:and: (in category 'private') ----- comparingStringBetweenIdentical: expected and: actual + + self deprecated. + ^ self comparingStringBetween: expected andIdentical: actual! - ^ 'Expected {1} and actual {2} are not identical.' format: { - expected printStringLimitedTo: 10. - actual printStringLimitedTo: 10. - }! Item was added: + ----- Method: TestCase>>comparingStringBetweenUnexpected:and: (in category 'private') ----- + comparingStringBetweenUnexpected: unexpected and: actual + + ^ 'Did not expect {1} but was {2}.' translated + format: { + unexpected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was added: + ----- Method: TestCase>>comparingStringBetweenUnexpected:andIdentical: (in category 'private') ----- + comparingStringBetweenUnexpected: expected andIdentical: actual + + ^ 'Unexpected {1} and actual {2} are identical.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was changed: ----- Method: TestCase>>deny:equals: (in category 'asserting') ----- deny: unexpected equals: actual + ^ self + deny: unexpected + equals: actual + description: nil! - ^self - deny: unexpected = actual - description: 'Actual equals unexpected' - ! Item was added: + ----- Method: TestCase>>deny:equals:description: (in category 'asserting') ----- + deny: unexpected equals: actual description: aStringOrBlock + + ^ self + deny: unexpected = actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetweenUnexpected: unexpected and: actual)]! Item was added: + ----- Method: TestCase>>deny:identical: (in category 'asserting') ----- + deny: unexpected identical: actual + + ^ self + deny: unexpected + identical: actual + description: nil! Item was added: + ----- Method: TestCase>>deny:identical:description: (in category 'asserting') ----- + deny: unexpected identical: actual description: aStringOrBlock + + ^ self + deny: unexpected == actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetweenUnexpected: unexpected andIdentical: actual)]! Item was added: + ----- Method: TestCase>>description:with: (in category 'private') ----- + description: aStringOrBlock with: reason + + | description | + description := aStringOrBlock value. + ^ description + ifNil: [reason] + ifNotNil: ['{1}: {2}' translated format: {description. reason}]! From vanessa at codefrau.net Fri Mar 5 23:40:39 2021 From: vanessa at codefrau.net (Vanessa Freudenberg) Date: Fri, 5 Mar 2021 15:40:39 -0800 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <1614985659729-0.post@n4.nabble.com> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> Message-ID: On Fri, Mar 5, 2021 at 3:07 PM Jaromir Matas wrote: > Hi Christoph, > > thanks for the link - it's a brilliant summary of the long detailed version > mentioned inside! Many thanks, Eliot! Hear, hear! Here's my mistake: I setup a `10 second wait` instead of `10 second*s* wait` > and Squeak interprets this typo as 1 second wait That sounds like a surprising feature/bug – either it should wait for 10 seconds, or it should throw an error, IMHO, but not simply disregard the receiver. I'd prefer if it just did the expected thing, making #second and #seconds synonyms. - Vanessa - so I was watching a history only - sorry for the noise :) > > best, > > > > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Sat Mar 6 08:34:44 2021 From: m at jaromir.net (Jaromir Matas) Date: Sat, 6 Mar 2021 02:34:44 -0600 (CST) Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> Message-ID: <1615019684983-0.post@n4.nabble.com> > That sounds like a surprising feature/bug – either it should wait for 10 seconds, or it should throw an error, IMHO, but not simply disregard the receiver. I'd prefer if it just did the expected thing, making #second and #seconds synonyms. +1. It bit me a couple of times already :) I'm not sure it's grammatically 100% correct but in English there's e.g. a five-second delay etc. sometimes written as five second delay... Number >> second ^ self sign seconds Number >> sign "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0." self > 0 ifTrue: [^1]. self < 0 ifTrue: [^-1]. ^0 ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Sat Mar 6 10:48:37 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Sat, 6 Mar 2021 11:48:37 +0100 Subject: [squeak-dev] Bag>>#rehash missing In-Reply-To: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> References: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> Message-ID: Hi Patrick. +1 on adding #rehash for Bag ... although it technically depends on #contentsClass ? Hmmm... +0.5 on making #rehash non-private. Hmm.... maybe "initialization" would be a fitting category. Well, definitely not "update" or something like that. Clients should normally not call it, right? Best, Marcel Am 05.03.2021 20:12:19 schrieb Rein, Patrick : Hi everyone, during a recent debugging session I noticed that Bag does not implement #rehash although it is, in essence, a hash-based collection and should therefore probably roughly adhere to the protocol of HashedCollection. Is there a good reason not to have #rehash on Bag? On a similar note: HashedCollection>>#rehash is in the `private` protocol but has various senders. As even the class comment mentions the usage of #rehash, I would also propose to move it out of the `private` protocol. :) Best wishes, Patrick -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Sat Mar 6 15:05:21 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sat, 6 Mar 2021 10:05:21 -0500 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <1615019684983-0.post@n4.nabble.com> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> Message-ID: <20210306150521.GA34636@shell.msen.com> On Sat, Mar 06, 2021 at 02:34:44AM -0600, Jaromir Matas wrote: > > That sounds like a surprising feature/bug ??? either it should wait for 10 > seconds, or it should throw an error, IMHO, but not simply disregard the > receiver. I'd prefer if it just did the expected thing, making #second and > #seconds synonyms. > > +1. It bit me a couple of times already :) > +1 My expectation would be that #second, #minute, #hour etc would be syntactic sugar. And I certainly would not expect "5 second" to mean one second duration. I note that we have several methods like this (second, minute, hour...) and they have Brent Pinkney's (brp) initials since 2004. I don't know if anyone depends on that existing behavior. Off topic, but there are other problems with these duration methods. They are defined in Number but round the duration magnitudes to whole seconds. And durations for 1 day or 1 week are undefinable due to daylight savings transitions and occasional leap seconds. Dave > I'm not sure it's grammatically 100% correct but in English there's e.g. a > five-second delay etc. sometimes written as five second delay... > > > Number >> second > > ^ self sign seconds > > Number >> sign > "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0." > > self > 0 ifTrue: [^1]. > self < 0 ifTrue: [^-1]. > ^0 > > > > > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > From commits at source.squeak.org Sat Mar 6 16:02:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sat, 6 Mar 2021 16:02:33 0000 Subject: [squeak-dev] The Inbox: Collections-ct.926.mcz Message-ID: Christoph Thiede uploaded a new version of Collections to project The Inbox: http://source.squeak.org/inbox/Collections-ct.926.mcz ==================== Summary ==================== Name: Collections-ct.926 Author: ct Time: 6 March 2021, 5:02:21.740032 pm UUID: 314b692a-8de7-6a46-80ad-9807771a7df2 Ancestors: Collections-jar.924 Implements missing HTML conversion on TextURL. =============== Diff against Collections-jar.924 =============== Item was added: + ----- Method: TextURL>>closeHtmlOn: (in category 'html') ----- + closeHtmlOn: aStream + + aStream nextPutAll: ''.! Item was added: + ----- Method: TextURL>>openHtmlOn: (in category 'html') ----- + openHtmlOn: aStream + + aStream + nextPutAll: ''.! From gettimothy at zoho.com Sat Mar 6 19:51:21 2021 From: gettimothy at zoho.com (gettimothy) Date: Sat, 06 Mar 2021 14:51:21 -0500 Subject: [squeak-dev] Squeak Winter Demos, 2021/03/06,        3 p.m. - 6 p.m. CET, virtual In-Reply-To: References: Message-ID: <17809182705.e47e859d47557.7261929616511810274@zoho.com> well, there is fashionably late and then there is the "order of magnitude late" that happens when i read CET as Central Standard Time . anyway, I was there, just 6 hours late.  Thanks for the invitation (: t ---- On Fri, 05 Mar 2021 07:55:45 -0500 Marcel Taeumel wrote ---- Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! Here are the information for the upcoming "Squeak Winter Demos", which you can also read about on https://squeak.de/news/. The login for the meeting is as follows: Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) https://uni-potsdam.zoom.us/j/61595939773 Meeting ID: 615 9593 9773 Passcode: 10202428 If you have anymore questions, feel free to contact me under mailto:marcel.taeumel at hpi.de. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: mailto:info at squeak-ev.de Internet: http://www.squeak.de/squeakev Am 09.02.2021 17:43:52 schrieb Marcel Taeumel : Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! We hope that you are doing well in these difficult times. Please take care of yourself and your peers. We cordially invite you to the “Squeak Winter Demos”, which are organized by the club of German-speaking Squeakers (“Squeak Deutschland e.V.”). We are going to fill that meeting with exciting talks, demos, and discussions. You want to attend or have more questions? Maybe even a proposal for a demo/talk/discussion? Feel free to talk to us so that we can better include your idea in the schedule. Since we want to keep the meeting as flexible as possible, every speaker should plan for about 20 minutes. When? Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) Where? The event will take place as a Zoom call. You need a webcam (maybe with a microphone) and a recent Web browser such as Firefox, Chrome, Edge, or Safari. Alternatively, you can download an app for your operating system via https://zoom.us/download. We will share the login data for the virtual meeting here on the day of the event. What will happen? We are currently in the process of planning talks and demos. Feel free to contribute with a short demo or experience report yourself – even on the fly if you want to! We welcome non-members to the meeting. :) Here is a preliminary agenda: Like the Babylonias: Programming with Examples Fast and colorful: OpenGL in Squeak Use the Entire Canvas: Block-based Programming Spot off, Morph on: Squeak Game Showcase 2020 It’s Broken! How to debug the debugger =) Social Media? A Telegram Bot for Squeak … and those who find the time but are not so fluent in German: We always welcome non-German-speaking Squeakers, too! We suppose that you will understand the live demonstrations anyway. :) We will be able to translate technical details or questions into English as well. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: mailto:info at squeak-ev.de Internet: http://www.squeak.de/squeakev -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Sat Mar 6 22:05:23 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sat, 6 Mar 2021 22:05:23 0000 Subject: [squeak-dev] The Trunk: EToys-nice.431.mcz Message-ID: Nicolas Cellier uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-nice.431.mcz ==================== Summary ==================== Name: EToys-nice.431 Author: nice Time: 6 March 2021, 11:05:12.703005 pm UUID: 11b19c19-a51f-7e4b-99b2-9f0497baebb1 Ancestors: EToys-mt.430 At the time this #MultiSymbolInWrongPlace backward compatibility workaround was written (before 2009), Dictionary was a subclass of Set, so the method did also rehash every Dictionary. Since 2010, Dictionary isNoMoreKindOf: Set, so if this workaround is of any use at all (?), restore its original intention, which is to rehash every HashedCollection. =============== Diff against EToys-mt.430 =============== Item was changed: ----- Method: ProjectLoading class>>loadImageSegment:fromDirectory:withProjectView:numberOfFontSubstitutes:substituteFont:mgr: (in category '*etoys') ----- loadImageSegment: morphOrList fromDirectory: aDirectoryOrNil withProjectView: existingView numberOfFontSubstitutes: numberOfFontSubstitutes substituteFont: substituteFont mgr: mgr | proj projectsToBeDeleted ef f | (f := (Flaps globalFlapTabWithID: 'Navigator' translated)) ifNotNil: [f hideFlap]. proj := morphOrList arrayOfRoots detect: [:mm | mm isKindOf: Project] ifNone: [^ nil]. numberOfFontSubstitutes > 0 ifTrue: [ proj projectParameterAt: #substitutedFont put: substituteFont]. ef := proj projectParameterAt: #eToysFont. (ef isNil or: [ef ~= substituteFont familySizeFace]) ifTrue: [ proj projectParameterAt: #substitutedFont put: substituteFont. ]. proj projectParameters at: #MultiSymbolInWrongPlace put: false. "Yoshiki did not put MultiSymbols into outPointers in older images!!" morphOrList arrayOfRoots do: [:obj | obj fixUponLoad: proj seg: morphOrList "imageSegment"]. (proj projectParameters at: #MultiSymbolInWrongPlace) ifTrue: [ + morphOrList arrayOfRoots do: [:obj | (obj isKindOf: HashedCollection ) ifTrue: [obj rehash]]]. - morphOrList arrayOfRoots do: [:obj | (obj isKindOf: Set) ifTrue: [obj rehash]]]. proj resourceManager: mgr. "proj versionFrom: preStream." proj lastDirectory: aDirectoryOrNil. proj setParent: Project current. projectsToBeDeleted := OrderedCollection new. existingView == #none ifFalse: [ self makeExistingView: existingView project: proj projectsToBeDeleted: projectsToBeDeleted]. ChangeSet allChangeSets add: proj changeSet. Project current projectParameters at: #deleteWhenEnteringNewProject ifPresent: [ :ignored | projectsToBeDeleted add: Project current. Project current removeParameter: #deleteWhenEnteringNewProject. ]. projectsToBeDeleted isEmpty ifFalse: [ proj projectParameters at: #projectsToBeDeleted put: projectsToBeDeleted. ]. proj removeParameter: #eToysFont. ^ proj! From nicolas.cellier.aka.nice at gmail.com Sat Mar 6 22:23:30 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Sat, 6 Mar 2021 23:23:30 +0100 Subject: [squeak-dev] Bag>>#rehash missing In-Reply-To: References: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> Message-ID: Hi all, I understand that we can have bags broken by mutation of some elements, and that rehash could be convenient while debugging. But on the other hand, I see quite few senders of rehash in the image, so I just wonder, are we gonna need it? I think that private not only covers methods that are really private and should not be sent by objects of other classes, it also often means not to be sent in normal circumstances, maybe something closer to privileged? Le sam. 6 mars 2021 à 11:48, Marcel Taeumel a écrit : > > Hi Patrick. > > +1 on adding #rehash for Bag ... although it technically depends on #contentsClass ? Hmmm... > > +0.5 on making #rehash non-private. Hmm.... maybe "initialization" would be a fitting category. Well, definitely not "update" or something like that. Clients should normally not call it, right? > > Best, > Marcel > > Am 05.03.2021 20:12:19 schrieb Rein, Patrick : > > Hi everyone, > > during a recent debugging session I noticed that Bag does not implement #rehash although it is, in essence, a hash-based collection and should therefore probably roughly adhere to the protocol of HashedCollection. Is there a good reason not to have #rehash on Bag? > > On a similar note: HashedCollection>>#rehash is in the `private` protocol but has various senders. As even the class comment mentions the usage of #rehash, I would also propose to move it out of the `private` protocol. :) > > Best wishes, > Patrick > > From commits at source.squeak.org Sun Mar 7 10:38:47 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sun, 7 Mar 2021 10:38:47 0000 Subject: [squeak-dev] The Inbox: Kernel-jar.1380.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-jar.1380.mcz ==================== Summary ==================== Name: Kernel-jar.1380 Author: jar Time: 7 March 2021, 11:38:42.526625 am UUID: a8d15458-c0fa-924f-ae0b-32e1354dbd77 Ancestors: Kernel-eem.1379 Refactoring #terminate to get rid of 'cannot return' errors etc. This is a follow up on the following threads: [1] http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html#a5127336 [2] http://forum.world.st/The-Inbox-Kernel-jar-1377-mcz-td5127438.html#a5127439 The enclosed Kernel file is intended for your consideration and testing only; it has not been thoroughly tested against any tools or the VM. =============== Diff against Kernel-eem.1379 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled. + Create a new bottom context for Process>>#terminated and make it the sender + of the new process for the benefit of Process>>#isTerminated." + + | newProcess bottomContext | + "" "Simulation guard" + newProcess := Process new. + bottomContext := Context + sender: nil + receiver: newProcess + method: (Process>>#terminated) + arguments: {}. + newProcess suspendedContext: (self asContextWithSender: bottomContext). + newProcess priority: Processor activePriority. + ^newProcess! - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" - ^Process - forContext: - [self value. - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." - Processor activeProcess suspend] asContext - priority: Processor activePriority! Item was changed: ----- Method: Process>>isSuspended (in category 'testing') ----- isSuspended + "A process is suspended if it has non-nil suspendedContext (e.g. new or + previously suspended with the suspend primitive) and is not terminated or + waiting in a scheduler or a semaphore queue (i.e. is not runnable or blocked)." + + ^myList isNil + and: [suspendedContext notNil + and: [self isTerminated not]]! - "A process is suspended if it has been suspended with the suspend primitive. - It is distinguishable from the active process and a terminated process by - having a non-nil suspendedContext that is either not the bottom context - or has not reached its endPC." - ^nil == myList - and: [nil ~~ suspendedContext - and: [suspendedContext isBottomContext - ifTrue: [suspendedContext closure - ifNil: [suspendedContext methodClass ~~ Process - or: [suspendedContext selector ~~ #terminate]] - ifNotNil: [suspendedContext pc < suspendedContext closure endPC]] - ifFalse: [true]]]! Item was changed: ----- Method: Process>>isTerminated (in category 'testing') ----- isTerminated + "Answer if the receiver is terminated, or at least terminating, i.e. if one + of the following conditions is met: + (1) the receiver is a defunct process (suspendedContext = nil or pc = nil) + (2) the receiver is suspended within Process>>terminated, i.e. terminated + (3) the suspendedContext is the bottomContext and the pc is at the endPC" + + self isActiveProcess ifTrue: [^false]. + ^suspendedContext isNil or: [suspendedContext isDead] + or: [suspendedContext methodClass == Process + and: [suspendedContext selector == #terminated]] + or: [suspendedContext isBottomContext + and: [suspendedContext atEnd]] + ! - "Answer if the receiver is terminated, or at least terminating." - self isActiveProcess ifTrue: [^ false]. - ^suspendedContext isNil - or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess. - If so, and the pc is at the endPC, the block has already sent and returned - from value and there is nothing more to do." - suspendedContext isBottomContext - and: [suspendedContext closure - ifNil: [suspendedContext methodClass == Process - and: [suspendedContext selector == #terminate]] - ifNotNil: [suspendedContext pc >= suspendedContext closure endPC]]]! Item was changed: ----- Method: Process>>terminate (in category 'changing process state') ----- terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. + "Now all work is done and the process can terminate" + ^self terminated]. - thisContext terminateTo: nil. - self suspend. - "If the process is resumed this will provoke a cannotReturn: error. - Would self debug: thisContext title: 'Resuming a terminated process' be better?" - ^self]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. - ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: [self debug: ctxt title: 'Unwind error during termination']. + "Set the receiver's context to Process>>#terminated for the benefit of isTerminated." + ctxt setSender: nil receiver: self method: (Process>>#terminated) arguments: {} + ]! - "Set the context to its endPC for the benefit of isTerminated." - ctxt pc: ctxt endPC]! Item was added: + ----- Method: Process>>terminated (in category 'changing process state') ----- + terminated + "When I reach this method, I'm terminated. + Suspending or terminating me is harmless." + + thisContext terminateTo: nil. "sets thisContext sender to nil" + self suspend. + ^thisContext restart! From m at jaromir.net Sun Mar 7 10:42:06 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 7 Mar 2021 04:42:06 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1380.mcz In-Reply-To: References: Message-ID: <1615113726960-0.post@n4.nabble.com> This is a follow up on the following threads: [1] http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html#a5127336 [2] http://forum.world.st/The-Inbox-Kernel-jar-1377-mcz-td5127438.html#a5127439 I've noticed resuming a terminated process ends up with "cannot return" and similar errors. I'd like to offer an alternative approach requiring just a few tiny changes: A process is terminated when it suspends itself or some other process does. When someone resumes a terminated process it continues and eventually fails. I'd like to propose a terminal method where all processes terminate: Process>> terminated "When I reach this method, I'm terminated. Suspending or terminating me is harmless." thisContext terminateTo: nil. "sets thisContext sender to nil" self suspend. ^thisContext restart This approach would simplify the #isTerminated method and would require just two little tweaks in the #terminate method: terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. "Now all work is done and the process can terminate" >>>> ^self terminated]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: [self debug: ctxt title: 'Unwind error during termination']. "Set the receiver's context to Process>>#terminated for the benefit of isTerminated." >>>> ctxt setSender: nil receiver: self method: (Process>>#terminated) arguments: {} ] When the active process terminates itself it sends itself the #terminated message parking itself in a "deathtrap". When a process is being terminated by another process its bottom context set to #terminated, effectively parking it in the same trap again. That's it. Now the terminated process may get resumed or terminated again with no error. Now, while we're at it we could take care of the processes that terminate "naturally" by reaching the end of their defining block. We need to refactor #newProcess to create the terminal bottom context (the trap) and set it as the initial sender of a newly created process for a block. If the process finishes without explicit termination or via an exception it'll automatically park itself in the #terminated facility: newProcess "Answer a Process running the code in the receiver. The process is not scheduled. Create a new bottom context for Process>>#terminated and make it the sender of the new process for the benefit of Process>>#isTerminated." | newProcess bottomContext | "" "Simulation guard" newProcess := Process new. bottomContext := Context sender: nil receiver: newProcess method: (Process>>#terminated) arguments: {}. newProcess suspendedContext: (self asContextWithSender: bottomContext). newProcess priority: Processor activePriority. ^newProcess The previously used #forContext:priority: had to be inlined because of the cross reference - the new bottom context refers to the new process and the new process refers back to the new bottom context. So at this point all "normal" processes (i.e. those created via newProcess) will terminate in #terminated regardless of whether they terminated themselves, were terminated by another party or just reached their closing square bracket. There's a group of potentially weird processes created via forContext:priority: that can choose their own fate and won't in general follow the above logic. For these cases I left the final condition in #isTerminate: they are also considered terminated when they reach their last instruction (and stay there): isTerminated ... suspendedContext isBottomContext and: [suspendedContext atEnd] Examples: p := Process forContext: [Processor activeProcess suspend] asContext priority: Processor activePriority +1. p resume Process forContext: [] asContext priority: 40 All tests are green but I'm aware this is just an idea that would have to be tested thoroughly against the VM and the debugger. Do you think this is something worth implementing though? For me, the code is more readable, process termination more orderly, no need for checking whether a process is terminated to avoid "cannot return" errors, the terminated processes are easily trackable and identifiable while debugging etc. The enclosed Kernel file is intended for your consideration and testing only; it has not been thoroughly tested against any tools or the VM. Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Sun Mar 7 19:42:57 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sun, 7 Mar 2021 19:42:57 0000 Subject: [squeak-dev] The Inbox: Morphic-ct.1733.mcz Message-ID: Christoph Thiede uploaded a new version of Morphic to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1733.mcz ==================== Summary ==================== Name: Morphic-ct.1733 Author: ct Time: 7 March 2021, 8:42:45.180906 pm UUID: b8246d49-b132-40af-8ad4-7428c544390c Ancestors: Morphic-mt.1731 Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection. =============== Diff against Morphic-mt.1731 =============== Item was changed: ----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') ----- inOutdent: aKeyboardEvent delta: delta "Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw" | realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize | - "Operate on entire lines, but remember the real selection for re-highlighting later" realStart := self startIndex. realStop := self stopIndex - 1. "Special case a caret on a line of its own, including weird case at end of paragraph" (realStart > realStop and: [realStart < 2 or: [(paragraph string at: realStart - 1) == Character cr or: [(paragraph string at: realStart - 1) == Character lf]]]) ifTrue: [delta < 0 ifTrue: [morph flash] ifFalse: [self replaceSelectionWith: Character tab asText. self selectAt: realStart + 1]. ^true]. lines := paragraph lines. startLine := paragraph lineIndexOfCharacterIndex: realStart. "start on a real line, not a wrapped line" [startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1]. stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop). start := (lines at: startLine) first. stop := (lines at: stopLine) last. "Pin the start of highlighting unless the selection starts a line" adjustStart := realStart > start. "Find the indentation of the least-indented non-blank line; never outdent more" "indentation := (startLine to: stopLine) inject: 1000 into: [:m :l | m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])]. indentation + delta <= 0 ifTrue: [^false]." numLines := stopLine + 1 - startLine. oldText := paragraph text copyFrom: start to: stop. newText := oldText species new: oldText size + ((numLines * delta) max: 0). "Do the actual work" newSize := 0. delta > 0 ifTrue: [| tabs | tabs := oldText species new: delta withAll: Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | + newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1. - startL < endWithoutDelimiters ifTrue: [newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1]. newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]] ifFalse: [| tab | tab := Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | | i | i := 0. [i + delta < 0 and: [ i + startL <= endWithoutDelimiters and: [(oldText at: i + startL) == tab]]] whileTrue: [i := i + 1]. newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]]. newSize < newText size ifTrue: [newText := newText copyFrom: 1 to: newSize]. "Adjust the range that will be highlighted later" adjustStart ifTrue: [realStart := (realStart + delta) max: start]. realStop := realStop + newSize - oldText size. "Replace selection" self selectInvisiblyFrom: start to: stop. self replaceSelectionWith: newText. self selectFrom: realStart to: realStop. "highlight only the original range" ^ true! From marcel.taeumel at hpi.de Mon Mar 8 07:23:00 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 08:23:00 +0100 Subject: [squeak-dev] Bag>>#rehash missing In-Reply-To: References: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> Message-ID: Hi Nicolas. > But on the other hand, I see quite few senders of rehash in the image, > so I just wonder, are we gonna need it? Hmm... I don't think that looking for senders will reveal the actual need for #rehash. Maybe broken bags remain unnoticed? At least a test with proper commentary about this issue might help users to figure out when to use #rehash. In Trunk, there are only a few, short-living examples of bags, which do not suffer from this problem. :-) In this particular case, some of our students stumbled upon this issue in a game and did not know how to interpret the effects to figure out what's going on. ... maybe we need some kind of hash-check test (tool) for the entire environment? The biggest issue here is to learn about the correct use of hashing. Best, Marcel Am 06.03.2021 23:23:56 schrieb Nicolas Cellier : Hi all, I understand that we can have bags broken by mutation of some elements, and that rehash could be convenient while debugging. But on the other hand, I see quite few senders of rehash in the image, so I just wonder, are we gonna need it? I think that private not only covers methods that are really private and should not be sent by objects of other classes, it also often means not to be sent in normal circumstances, maybe something closer to privileged? Le sam. 6 mars 2021 à 11:48, Marcel Taeumel a écrit : > > Hi Patrick. > > +1 on adding #rehash for Bag ... although it technically depends on #contentsClass ? Hmmm... > > +0.5 on making #rehash non-private. Hmm.... maybe "initialization" would be a fitting category. Well, definitely not "update" or something like that. Clients should normally not call it, right? > > Best, > Marcel > > Am 05.03.2021 20:12:19 schrieb Rein, Patrick : > > Hi everyone, > > during a recent debugging session I noticed that Bag does not implement #rehash although it is, in essence, a hash-based collection and should therefore probably roughly adhere to the protocol of HashedCollection. Is there a good reason not to have #rehash on Bag? > > On a similar note: HashedCollection>>#rehash is in the `private` protocol but has various senders. As even the class comment mentions the usage of #rehash, I would also propose to move it out of the `private` protocol. :) > > Best wishes, > Patrick > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 07:27:02 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 08:27:02 +0100 Subject: [squeak-dev] Squeak Winter Demos, 2021/03/06,        3 p.m. - 6 p.m. CET, virtual In-Reply-To: <17809182705.e47e859d47557.7261929616511810274@zoho.com> References: <17809182705.e47e859d47557.7261929616511810274@zoho.com> Message-ID: Hi Timothy, oh no! :-( Yeah, CT, CST, CDT, CET, CEST, ... this can be very confusing. Maybe I should spell it out the next time. I recall a similar issue on a conference last year. Best, Marcel Am 06.03.2021 20:51:29 schrieb gettimothy : well, there is fashionably late and then there is the "order of magnitude late" that happens when i read CET as Central Standard Time . anyway, I was there, just 6 hours late.  Thanks for the invitation (: t ---- On Fri, 05 Mar 2021 07:55:45 -0500 Marcel Taeumel wrote ---- Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! Here are the information for the upcoming "Squeak Winter Demos", which you can also read about on https://squeak.de/news/ [https://squeak.de/news/]. The login for the meeting is as follows: Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) https://uni-potsdam.zoom.us/j/61595939773 [https://uni-potsdam.zoom.us/j/61595939773] Meeting ID: 615 9593 9773 Passcode: 10202428 If you have anymore questions, feel free to contact me under marcel.taeumel at hpi.de [mailto:marcel.taeumel at hpi.de]. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: info at squeak-ev.de [mailto:info at squeak-ev.de] Internet: http://www.squeak.de/squeakev [http://www.squeak.de/squeakev] Am 09.02.2021 17:43:52 schrieb Marcel Taeumel : Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! We hope that you are doing well in these difficult times. Please take care of yourself and your peers. We cordially invite you to the “Squeak Winter Demos”, which are organized by the club of German-speaking Squeakers (“Squeak Deutschland e.V.”). We are going to fill that meeting with exciting talks, demos, and discussions. You want to attend or have more questions? Maybe even a proposal for a demo/talk/discussion? Feel free to talk to us so that we can better include your idea in the schedule. Since we want to keep the meeting as flexible as possible, every speaker should plan for about 20 minutes. When? Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) Where? The event will take place as a Zoom call. You need a webcam (maybe with a microphone) and a recent Web browser such as Firefox, Chrome, Edge, or Safari. Alternatively, you can download an app for your operating system via https://zoom.us/download [https://zoom.us/download]. We will share the login data for the virtual meeting here on the day of the event. What will happen? We are currently in the process of planning talks and demos. Feel free to contribute with a short demo or experience report yourself – even on the fly if you want to! We welcome non-members to the meeting. :) Here is a preliminary agenda: * Like the Babylonias: Programming with Examples * Fast and colorful: OpenGL in Squeak * Use the Entire Canvas: Block-based Programming * Spot off, Morph on: Squeak Game Showcase 2020 * It’s Broken! How to debug the debugger =) * Social Media? A Telegram Bot for Squeak … and those who find the time but are not so fluent in German: We always welcome non-German-speaking Squeakers, too! We suppose that you will understand the live demonstrations anyway. :) We will be able to translate technical details or questions into English as well. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: info at squeak-ev.de [mailto:info at squeak-ev.de] Internet: http://www.squeak.de/squeakev [http://www.squeak.de/squeakev] -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 09:43:12 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 10:43:12 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Message-ID: Hi all! :-) Here is an interesting issue that I repeatedly come across when it comes to enumerating a (sequenceable/ordered) collection up to a certain element, while collecting (i.e. mapping) new elements from that collection. It seems rather tedious to express in code, meaning more than 2-3 lines and maybe involving even temporary variables. Our stream protocol has #upTo:, which works when you know about the specific element you are looking for. It does not work, however, when you just have an indirect query that should match. Here is an example. From a list of integer numbers, extract all even ones up to (including) 50, then square those numbers. (1 to: 100)    select: [:num | num <= 50 and: [num even]]    thenCollect: [:num | num * num]. A stream-based approach to shorten the predicate using #upTo: could look like this: ((1 to: 100) readStream upTo: 50)    select: [:num | num even]    thenCollect: [:num | num * num]. Now imagine that, unfortunately, we don't know about "50" but only a query, say "a number that is squared 2500". Since #upTo: cannot do that and I do not want to jump collection-stream-collection for this issue, the non-stream approach could look like this: (1 to: 100)    select: [:num | (num * num <= 2500) and: [num even]]    thenCollect: [:num | num * num]. Yet, this is still not my actual issue. What if that collection is not ordered at all but only has a stable sequence? Then we would need to mark the specific element and then reject every element that comes after that. (Note that we replaced #<= with #= to indicate "sequence" instead of "order".) | found | found := false. (1 to: 100)    select: [:num |       found := found or: [num * num = 2500].       found not and: [num even]]    thenCollect: [:num | num * num]. Uh oh! We just skipped the stop element itself. What if we want to include it? Maybe like this: | found | found := false. (1 to: 100)    select: [:num | | firstMatch |       firstMatch := found not and: [num * num = 2500].       found := found | firstMatch.       found not | firstMatch and: [num even]]    thenCollect: [:num | num * num]. Now this looks like a rather complicated implementation for a simple query. Let me give you a last approach using the infamous #valueWithExit. | list stop select collect result | list := 1 to: 100. stop := [:num | num * num = 2500]. select := [:num | num even]. collect := [:num | num * num]. result := OrderedCollection new. [:break |    list do: [:num |       (select value: num) ifTrue: [result add: (collect value: num)].       (stop value: num) ifTrue: [break value]]. ] valueWithExit. Phew. Is there a simpler approach to this problem? I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. aButton withAllOwners    collect: [:morph | morph color]    until: [:morph | morph isSystemWindow]. (aButton withAllOwners readStream    upToSatisfying: [:morph | isSystemWindow])    collect: [:morph | morph color]. Best, Marcel -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 09:52:54 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 10:52:54 +0100 Subject: [squeak-dev] The Inbox: Morphic-ct.1733.mcz In-Reply-To: References: Message-ID: Hi Christoph, why is this a bug? A quick experiment in Sublime Text suggested that this might be the expected behavior. At least for actually empty lines, having not a single white-space character. Best, Marcle Am 07.03.2021 20:43:09 schrieb commits at source.squeak.org : Christoph Thiede uploaded a new version of Morphic to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1733.mcz ==================== Summary ==================== Name: Morphic-ct.1733 Author: ct Time: 7 March 2021, 8:42:45.180906 pm UUID: b8246d49-b132-40af-8ad4-7428c544390c Ancestors: Morphic-mt.1731 Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection. =============== Diff against Morphic-mt.1731 =============== Item was changed: ----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') ----- inOutdent: aKeyboardEvent delta: delta "Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw" | realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize | - "Operate on entire lines, but remember the real selection for re-highlighting later" realStart := self startIndex. realStop := self stopIndex - 1. "Special case a caret on a line of its own, including weird case at end of paragraph" (realStart > realStop and: [realStart ifTrue: [delta ifTrue: [morph flash] ifFalse: [self replaceSelectionWith: Character tab asText. self selectAt: realStart + 1]. ^true]. lines := paragraph lines. startLine := paragraph lineIndexOfCharacterIndex: realStart. "start on a real line, not a wrapped line" [startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1]. stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop). start := (lines at: startLine) first. stop := (lines at: stopLine) last. "Pin the start of highlighting unless the selection starts a line" adjustStart := realStart > start. "Find the indentation of the least-indented non-blank line; never outdent more" "indentation := (startLine to: stopLine) inject: 1000 into: [:m :l | m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])]. indentation + delta newSize := 0. delta > 0 ifTrue: [| tabs | tabs := oldText species new: delta withAll: Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | + newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1. - startL newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]] ifFalse: [| tab | tab := Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | | i | i := 0. [i + delta newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]]. newSize "Adjust the range that will be highlighted later" adjustStart ifTrue: [realStart := (realStart + delta) max: start]. realStop := realStop + newSize - oldText size. "Replace selection" self selectInvisiblyFrom: start to: stop. self replaceSelectionWith: newText. self selectFrom: realStart to: realStop. "highlight only the original range" ^ true! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 09:55:19 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 10:55:19 +0100 Subject: [squeak-dev] The Inbox: Morphic-ct.1733.mcz In-Reply-To: References: Message-ID: Note that "actually empty" would translate to "single indent/tab" in Squeak because of the way method source code is presented. Best, Marcel Am 08.03.2021 10:52:54 schrieb Marcel Taeumel : Hi Christoph, why is this a bug? A quick experiment in Sublime Text suggested that this might be the expected behavior. At least for actually empty lines, having not a single white-space character. Best, Marcle Am 07.03.2021 20:43:09 schrieb commits at source.squeak.org : Christoph Thiede uploaded a new version of Morphic to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1733.mcz ==================== Summary ==================== Name: Morphic-ct.1733 Author: ct Time: 7 March 2021, 8:42:45.180906 pm UUID: b8246d49-b132-40af-8ad4-7428c544390c Ancestors: Morphic-mt.1731 Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection. =============== Diff against Morphic-mt.1731 =============== Item was changed: ----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') ----- inOutdent: aKeyboardEvent delta: delta "Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw" | realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize | - "Operate on entire lines, but remember the real selection for re-highlighting later" realStart := self startIndex. realStop := self stopIndex - 1. "Special case a caret on a line of its own, including weird case at end of paragraph" (realStart > realStop and: [realStart ifTrue: [delta ifTrue: [morph flash] ifFalse: [self replaceSelectionWith: Character tab asText. self selectAt: realStart + 1]. ^true]. lines := paragraph lines. startLine := paragraph lineIndexOfCharacterIndex: realStart. "start on a real line, not a wrapped line" [startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1]. stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop). start := (lines at: startLine) first. stop := (lines at: stopLine) last. "Pin the start of highlighting unless the selection starts a line" adjustStart := realStart > start. "Find the indentation of the least-indented non-blank line; never outdent more" "indentation := (startLine to: stopLine) inject: 1000 into: [:m :l | m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])]. indentation + delta newSize := 0. delta > 0 ifTrue: [| tabs | tabs := oldText species new: delta withAll: Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | + newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1. - startL newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]] ifFalse: [| tab | tab := Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | | i | i := 0. [i + delta newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]]. newSize "Adjust the range that will be highlighted later" adjustStart ifTrue: [realStart := (realStart + delta) max: start]. realStop := realStop + newSize - oldText size. "Replace selection" self selectInvisiblyFrom: start to: stop. self replaceSelectionWith: newText. self selectFrom: realStart to: realStop. "highlight only the original range" ^ true! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 10:05:56 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 11:05:56 +0100 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <20210306150521.GA34636@shell.msen.com> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> Message-ID: Hi all!   I think that we should change (and test) all those singular cases. And maybe add lower-case versions for #microSeconds, #milliSeconds, and #nanoSeconds to make it proper English. :-) Best, Marcel Am 06.03.2021 16:05:28 schrieb David T. Lewis : On Sat, Mar 06, 2021 at 02:34:44AM -0600, Jaromir Matas wrote: > > That sounds like a surprising feature/bug ??? either it should wait for 10 > seconds, or it should throw an error, IMHO, but not simply disregard the > receiver. I'd prefer if it just did the expected thing, making #second and > #seconds synonyms. > > +1. It bit me a couple of times already :) > +1 My expectation would be that #second, #minute, #hour etc would be syntactic sugar. And I certainly would not expect "5 second" to mean one second duration. I note that we have several methods like this (second, minute, hour...) and they have Brent Pinkney's (brp) initials since 2004. I don't know if anyone depends on that existing behavior. Off topic, but there are other problems with these duration methods. They are defined in Number but round the duration magnitudes to whole seconds. And durations for 1 day or 1 week are undefinable due to daylight savings transitions and occasional leap seconds. Dave > I'm not sure it's grammatically 100% correct but in English there's e.g. a > five-second delay etc. sometimes written as five second delay... > > > Number >> second > > ^ self sign seconds > > Number >> sign > "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0." > > self > 0 ifTrue: [^1]. > self < 0 ifTrue: [^-1]. > ^0 > > > > > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 10:09:08 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 11:09:08 +0100 Subject: [squeak-dev] The Inbox: SUnit-ct.132.mcz In-Reply-To: References: Message-ID: > Replaces SUnit-ct.126 which can be moved into the treated inbox. And what about SUnit-ct.127? Best, Marcel Am 06.03.2021 00:35:43 schrieb commits at source.squeak.org : A new version of SUnit was added to project The Inbox: http://source.squeak.org/inbox/SUnit-ct.132.mcz ==================== Summary ==================== Name: SUnit-ct.132 Author: ct Time: 6 March 2021, 12:35:33.710439 am UUID: 98d667df-13be-d148-9117-0b214c9adb3f Ancestors: SUnit-nice.124 Refactors and completes equality assertions - Add #deny:equals:description:, #deny:identical:, and #deny:identical:description: - Revise default description message for #deny:equals:, aligning it to #assert:equals: description - Make equality assertions capable of lazy descriptions (aStringOrBlock), aligning them to #assert:description: etc. - Add multilingual support for default description messages - Some internal refactoring - Improve test coverage of these assertions in SUnitTest Thanks to Marcel for pointing to the idea! Uploaded again to resolve conflicts with SUnit-pre.122 (recategorization). Replaces SUnit-ct.126 which can be moved into the treated inbox. :-) =============== Diff against SUnit-nice.124 =============== Item was added: + ----- Method: SUnitTest>>testAssertEquals (in category 'tests') ----- + testAssertEquals + + | a b | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self assert: a equals: a copy] raise: TestFailure. + + self should: [self assert: a equals: b] raise: TestFailure. + + [self assert: a equals: b] + on: TestFailure do: [:ex | + | error | + error := ex messageText. + self + assert: (error includesSubstring: a) + description: 'Error message doesn''t include the expected value'. + self + assert: (error includesSubstring: b) + description: 'Error message doesn''t include the actual value'].! Item was added: + ----- Method: SUnitTest>>testAssertEqualsDescription (in category 'tests') ----- + testAssertEqualsDescription + + | a b called | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self assert: a equals: a copy description: 'A description42'] raise: TestFailure. + + self should: [self assert: a equals: b description: 'A description42'] raise: TestFailure. + + [self assert: a equals: b description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self assert: a equals: a description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self assert: a equals: b description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! Item was changed: ----- Method: SUnitTest>>testAssertIdentical (in category 'tests') ----- testAssertIdentical + | a b | a := 'foo'. b := 'bar'. + + self shouldnt: [self assert: a identical: a] raise: TestFailure. + self should: [self assert: a identical: b] raise: TestFailure. + + [self assert: a identical: b] + on: TestFailure do: [:ex | + | error | + error := ex messageText. + self + assert: (error includesSubstring: a) + description: 'Error message doesn''t include the expected value'. + self + assert: (error includesSubstring: b) + description: 'Error message doesn''t include the actual value'].! - [self assert: a identical: b] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: a) description: 'Error message doesn''t include the expected value'. - self assert: (error includesSubstring: b) description: 'Error message doesn''t include the expected value'].! Item was changed: ----- Method: SUnitTest>>testAssertIdenticalDescription (in category 'tests') ----- testAssertIdenticalDescription + + | a b called | - | a b | a := 'foo'. b := a copy. + + self shouldnt: [self assert: a identical: a description: 'A description42'] raise: TestFailure. + + self should: [self assert: a identical: b description: 'A description42'] raise: TestFailure. + + [self assert: a identical: b description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self assert: a identical: a description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self assert: a identical: b description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! - self should: [self assert: a identical: b description: 'A desciption'] raise: TestFailure. - [self assert: a identical: b description: 'A desciption'] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: 'A desciption') description: 'Error message doesn''t give you the description'].! Item was changed: ----- Method: SUnitTest>>testAssertIdenticalWithEqualObjects (in category 'tests') ----- testAssertIdenticalWithEqualObjects + | a b | a := 'foo'. b := a copy. + self should: [self assert: a identical: b] raise: TestFailure. + + [self assert: a identical: b] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'not identical') + description: 'Error message doesn''t say the two things aren''t identical'].! - [self assert: a identical: b] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: 'not identical') description: 'Error message doesn''t say the two things aren''t identical'].! Item was added: + ----- Method: SUnitTest>>testDenyEquals (in category 'tests') ----- + testDenyEquals + + | a b | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self deny: a equals: b] raise: TestFailure. + + self should: [self deny: a equals: a copy] raise: TestFailure. + + [self deny: a equals: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: a) + description: 'Error message doesn''t include the unexpected value'].! Item was added: + ----- Method: SUnitTest>>testDenyEqualsDescription (in category 'tests') ----- + testDenyEqualsDescription + + | a b called | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self deny: a equals: b description: 'A description42'] raise: TestFailure. + + self should: [self deny: a equals: a copy description: 'A description42'] raise: TestFailure. + + [self deny: a equals: a description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self deny: a equals: b description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self deny: a equals: a description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! Item was added: + ----- Method: SUnitTest>>testDenyIdentical (in category 'tests') ----- + testDenyIdentical + + | a b | + a := 'foo'. + b := 'bar'. + self shouldnt: [self deny: a identical: b] raise: TestFailure. + self should: [self deny: a identical: a] raise: TestFailure. + [self deny: a identical: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: a) + description: 'Error message doesn''t include the unexpected value'].! Item was added: + ----- Method: SUnitTest>>testDenyIdenticalDescription (in category 'tests') ----- + testDenyIdenticalDescription + + | a b called | + a := 'foo'. + b := a copy. + + self shouldnt: [self deny: a identical: b description: 'A description42'] raise: TestFailure. + + self should: [self deny: a identical: a description: 'A description42'] raise: TestFailure. + + [self deny: a identical: a description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self deny: a identical: b description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self deny: a identical: a description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the description'].! Item was added: + ----- Method: SUnitTest>>testDenyIdenticalWithEqualObjects (in category 'tests') ----- + testDenyIdenticalWithEqualObjects + + | a b | + a := 'foo'. + b := a copy. + self should: [self deny: a identical: a] raise: TestFailure. + [self deny: a identical: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'identical') + description: 'Error message doesn''t say the two things are identical'].! Item was changed: ----- Method: TestCase>>assert:equals: (in category 'asserting') ----- assert: expected equals: actual + ^ self + assert: expected + equals: actual + description: nil - ^self - assert: expected = actual - description: [ self comparingStringBetween: expected and: actual ] ! Item was changed: ----- Method: TestCase>>assert:equals:description: (in category 'asserting') ----- + assert: expected equals: actual description: aStringOrBlock - assert: expected equals: actual description: aString + ^ self - ^self assert: expected = actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetween: expected and: actual)]! - description: [ aString , ': ', (self comparingStringBetween: expected and: actual) ]! Item was changed: ----- Method: TestCase>>assert:identical: (in category 'asserting') ----- assert: expected identical: actual + ^ self + assert: expected + identical: actual + description: nil! - ^self - assert: expected == actual - description: [ self comparingStringBetweenIdentical: expected and: actual ] - ! Item was changed: ----- Method: TestCase>>assert:identical:description: (in category 'asserting') ----- + assert: expected identical: actual description: aStringOrBlock - assert: expected identical: actual description: aString + ^ self - ^self assert: expected == actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetween: expected andIdentical: actual)]! - description: [ aString , ': ', (self comparingStringBetweenIdentical: expected and: actual) ]! Item was changed: ----- Method: TestCase>>comparingStringBetween:and: (in category 'private') ----- comparingStringBetween: expected and: actual + + ^ 'Expected {1} but was {2}.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! - ^ String streamContents: [:stream | - stream - nextPutAll: 'Expected '; - nextPutAll: (expected printStringLimitedTo: 10); - nextPutAll: ' but was '; - nextPutAll: (actual printStringLimitedTo: 10); - nextPutAll: '.' - ]! Item was added: + ----- Method: TestCase>>comparingStringBetween:andIdentical: (in category 'private') ----- + comparingStringBetween: expected andIdentical: actual + + ^ 'Expected {1} and actual {2} are not identical.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was changed: ----- Method: TestCase>>comparingStringBetweenIdentical:and: (in category 'private') ----- comparingStringBetweenIdentical: expected and: actual + + self deprecated. + ^ self comparingStringBetween: expected andIdentical: actual! - ^ 'Expected {1} and actual {2} are not identical.' format: { - expected printStringLimitedTo: 10. - actual printStringLimitedTo: 10. - }! Item was added: + ----- Method: TestCase>>comparingStringBetweenUnexpected:and: (in category 'private') ----- + comparingStringBetweenUnexpected: unexpected and: actual + + ^ 'Did not expect {1} but was {2}.' translated + format: { + unexpected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was added: + ----- Method: TestCase>>comparingStringBetweenUnexpected:andIdentical: (in category 'private') ----- + comparingStringBetweenUnexpected: expected andIdentical: actual + + ^ 'Unexpected {1} and actual {2} are identical.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was changed: ----- Method: TestCase>>deny:equals: (in category 'asserting') ----- deny: unexpected equals: actual + ^ self + deny: unexpected + equals: actual + description: nil! - ^self - deny: unexpected = actual - description: 'Actual equals unexpected' - ! Item was added: + ----- Method: TestCase>>deny:equals:description: (in category 'asserting') ----- + deny: unexpected equals: actual description: aStringOrBlock + + ^ self + deny: unexpected = actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetweenUnexpected: unexpected and: actual)]! Item was added: + ----- Method: TestCase>>deny:identical: (in category 'asserting') ----- + deny: unexpected identical: actual + + ^ self + deny: unexpected + identical: actual + description: nil! Item was added: + ----- Method: TestCase>>deny:identical:description: (in category 'asserting') ----- + deny: unexpected identical: actual description: aStringOrBlock + + ^ self + deny: unexpected == actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetweenUnexpected: unexpected andIdentical: actual)]! Item was added: + ----- Method: TestCase>>description:with: (in category 'private') ----- + description: aStringOrBlock with: reason + + | description | + description := aStringOrBlock value. + ^ description + ifNil: [reason] + ifNotNil: ['{1}: {2}' translated format: {description. reason}]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicolas.cellier.aka.nice at gmail.com Mon Mar 8 10:42:10 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Mon, 8 Mar 2021 11:42:10 +0100 Subject: [squeak-dev] Bag>>#rehash missing In-Reply-To: References: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> Message-ID: Le lun. 8 mars 2021 à 08:23, Marcel Taeumel a écrit : > > Hi Nicolas. > > > But on the other hand, I see quite few senders of rehash in the image, > > so I just wonder, are we gonna need it? > > Hmm... I don't think that looking for senders will reveal the actual need for #rehash. Maybe broken bags remain unnoticed? At least a test with proper commentary about this issue might help users to figure out when to use #rehash. In Trunk, there are only a few, short-living examples of bags, which do not suffer from this problem. :-) > > In this particular case, some of our students stumbled upon this issue in a game and did not know how to interpret the effects to figure out what's going on. ... maybe we need some kind of hash-check test (tool) for the entire environment? The biggest issue here is to learn about the correct use of hashing. > > Best, > Marcel > Sure, Bag problems have great chances to get unnoticed because Bags are rarely used in practice. However, it's not a problem of Bag per se, it's a problem of using HashedCollection in general in case when we do not restrict object mutations... My sentiment was that rehash was more a utility method than something needed with regard to standard usage of rehash currently in image. But of course, if you think that it's a useful utility (pleonasm ?), just go. > Am 06.03.2021 23:23:56 schrieb Nicolas Cellier : > > Hi all, > I understand that we can have bags broken by mutation of some > elements, and that rehash could be convenient while debugging. > But on the other hand, I see quite few senders of rehash in the image, > so I just wonder, are we gonna need it? > > I think that private not only covers methods that are really private > and should not be sent by objects of other classes, it also often > means not to be sent in normal circumstances, maybe something closer > to privileged? > > Le sam. 6 mars 2021 à 11:48, Marcel Taeumel a écrit : > > > > Hi Patrick. > > > > +1 on adding #rehash for Bag ... although it technically depends on #contentsClass ? Hmmm... > > > > +0.5 on making #rehash non-private. Hmm.... maybe "initialization" would be a fitting category. Well, definitely not "update" or something like that. Clients should normally not call it, right? > > > > Best, > > Marcel > > > > Am 05.03.2021 20:12:19 schrieb Rein, Patrick : > > > > Hi everyone, > > > > during a recent debugging session I noticed that Bag does not implement #rehash although it is, in essence, a hash-based collection and should therefore probably roughly adhere to the protocol of HashedCollection. Is there a good reason not to have #rehash on Bag? > > > > On a similar note: HashedCollection>>#rehash is in the `private` protocol but has various senders. As even the class comment mentions the usage of #rehash, I would also propose to move it out of the `private` protocol. :) > > > > Best wishes, > > Patrick > > > > > > From nicolas.cellier.aka.nice at gmail.com Mon Mar 8 11:22:16 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Mon, 8 Mar 2021 12:22:16 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: Message-ID: First, concerning the inclusion of the matching element, Stream upTo: has always excluded that element. VW has introduced through: which is the inclusive variant of upTo: I notice that we have adopted that semantic in Collection protocol with copyUpThrough: versus copyUpTo: , but did not implement through: in Stream... My advice would be to stick with those semantics as much as possible to avoid confusion*. Concerning the usage of a predicate rather than an element, I don't see an existing method indeed. It could be something like: ^self first: (self findFirst: predicate), but that would answer an empty collection when no element matches, contrary to copyUpTo:... The handling of zero makes it mandatory to use periphrases (and temps). I see that we lack a findFirst:ifNone:... Of course, if you want then to collect:, then it would cost an intermediate collection creation and two scans. The alternative would be to use lazy proxies like in Xtreams, selecting: instead of select, collecting: instead of collect:... By the way, there is already the vocable limiting: in Xtreams, that must be fed with a position, but findFirst: is not yet implemented (Xtreams are not necessarily positionable). Maybe we should inquire what clojure and the like have to propose in this domain for some refreshing ideas... https://clojuredocs.org/clojure.core/for *side note: there's already some level of confusion between dialects. For example, upTo: is not inclusive, but leave the stream position AFTER the matching element. 'abcdeh' readStream upTo: $c; next -> $d But that's not necessarily the case with upToAll: 'abcdeh' readStream upToAll: 'cd'; next -> $e in Squeak 'abcdeh' readStream upToAll: 'cd'; next -> $c in VW Le lun. 8 mars 2021 à 10:43, Marcel Taeumel a écrit : > > Hi all! :-) > > Here is an interesting issue that I repeatedly come across when it comes to enumerating a (sequenceable/ordered) collection up to a certain element, while collecting (i.e. mapping) new elements from that collection. It seems rather tedious to express in code, meaning more than 2-3 lines and maybe involving even temporary variables. > > Our stream protocol has #upTo:, which works when you know about the specific element you are looking for. It does not work, however, when you just have an indirect query that should match. > > Here is an example. From a list of integer numbers, extract all even ones up to (including) 50, then square those numbers. > > (1 to: 100) > select: [:num | num <= 50 and: [num even]] > thenCollect: [:num | num * num]. > > A stream-based approach to shorten the predicate using #upTo: could look like this: > > ((1 to: 100) readStream upTo: 50) > select: [:num | num even] > thenCollect: [:num | num * num]. > > Now imagine that, unfortunately, we don't know about "50" but only a query, say "a number that is squared 2500". Since #upTo: cannot do that and I do not want to jump collection-stream-collection for this issue, the non-stream approach could look like this: > > (1 to: 100) > select: [:num | (num * num <= 2500) and: [num even]] > thenCollect: [:num | num * num]. > > Yet, this is still not my actual issue. What if that collection is not ordered at all but only has a stable sequence? Then we would need to mark the specific element and then reject every element that comes after that. (Note that we replaced #<= with #= to indicate "sequence" instead of "order".) > > | found | > found := false. > (1 to: 100) > select: [:num | > found := found or: [num * num = 2500]. > found not and: [num even]] > thenCollect: [:num | num * num]. > > Uh oh! We just skipped the stop element itself. What if we want to include it? Maybe like this: > > | found | > found := false. > (1 to: 100) > select: [:num | | firstMatch | > firstMatch := found not and: [num * num = 2500]. > found := found | firstMatch. > found not | firstMatch and: [num even]] > thenCollect: [:num | num * num]. > > Now this looks like a rather complicated implementation for a simple query. Let me give you a last approach using the infamous #valueWithExit. > > | list stop select collect result | > list := 1 to: 100. > stop := [:num | num * num = 2500]. > select := [:num | num even]. > collect := [:num | num * num]. > result := OrderedCollection new. > [:break | > list do: [:num | > (select value: num) ifTrue: [result add: (collect value: num)]. > (stop value: num) ifTrue: [break value]]. > ] valueWithExit. > > Phew. Is there a simpler approach to this problem? I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners > collect: [:morph | morph color] > until: [:morph | morph isSystemWindow]. > > (aButton withAllOwners readStream > upToSatisfying: [:morph | isSystemWindow]) > collect: [:morph | morph color]. > > Best, > Marcel > From Christoph.Thiede at student.hpi.uni-potsdam.de Mon Mar 8 12:27:57 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Mon, 8 Mar 2021 12:27:57 +0000 Subject: [squeak-dev] The Inbox: SUnit-ct.132.mcz In-Reply-To: References: , Message-ID: <0b0aa1328a484d54ac3f28bb02aab874@student.hpi.uni-potsdam.de> > And what about SUnit-ct.127? Well, I think some people have mentioned good reasons against putting domain-specific things such as Regex into the central SUnit package, so it could go to the treated inbox, too, I guess. But maybe we could support the regex assertion selectors as extension methods from the Regex package? Or would this be a bad idea because Regex would depend on SUnit then? Maybe a Regex-SUnit package, similar to ToolBuilder-SUnit? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Montag, 8. März 2021 11:09:08 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: SUnit-ct.132.mcz > Replaces SUnit-ct.126 which can be moved into the treated inbox. And what about SUnit-ct.127? Best, Marcel Am 06.03.2021 00:35:43 schrieb commits at source.squeak.org : A new version of SUnit was added to project The Inbox: http://source.squeak.org/inbox/SUnit-ct.132.mcz ==================== Summary ==================== Name: SUnit-ct.132 Author: ct Time: 6 March 2021, 12:35:33.710439 am UUID: 98d667df-13be-d148-9117-0b214c9adb3f Ancestors: SUnit-nice.124 Refactors and completes equality assertions - Add #deny:equals:description:, #deny:identical:, and #deny:identical:description: - Revise default description message for #deny:equals:, aligning it to #assert:equals: description - Make equality assertions capable of lazy descriptions (aStringOrBlock), aligning them to #assert:description: etc. - Add multilingual support for default description messages - Some internal refactoring - Improve test coverage of these assertions in SUnitTest Thanks to Marcel for pointing to the idea! Uploaded again to resolve conflicts with SUnit-pre.122 (recategorization). Replaces SUnit-ct.126 which can be moved into the treated inbox. :-) =============== Diff against SUnit-nice.124 =============== Item was added: + ----- Method: SUnitTest>>testAssertEquals (in category 'tests') ----- + testAssertEquals + + | a b | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self assert: a equals: a copy] raise: TestFailure. + + self should: [self assert: a equals: b] raise: TestFailure. + + [self assert: a equals: b] + on: TestFailure do: [:ex | + | error | + error := ex messageText. + self + assert: (error includesSubstring: a) + description: 'Error message doesn''t include the expected value'. + self + assert: (error includesSubstring: b) + description: 'Error message doesn''t include the actual value'].! Item was added: + ----- Method: SUnitTest>>testAssertEqualsDescription (in category 'tests') ----- + testAssertEqualsDescription + + | a b called | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self assert: a equals: a copy description: 'A description42'] raise: TestFailure. + + self should: [self assert: a equals: b description: 'A description42'] raise: TestFailure. + + [self assert: a equals: b description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self assert: a equals: a description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self assert: a equals: b description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! Item was changed: ----- Method: SUnitTest>>testAssertIdentical (in category 'tests') ----- testAssertIdentical + | a b | a := 'foo'. b := 'bar'. + + self shouldnt: [self assert: a identical: a] raise: TestFailure. + self should: [self assert: a identical: b] raise: TestFailure. + + [self assert: a identical: b] + on: TestFailure do: [:ex | + | error | + error := ex messageText. + self + assert: (error includesSubstring: a) + description: 'Error message doesn''t include the expected value'. + self + assert: (error includesSubstring: b) + description: 'Error message doesn''t include the actual value'].! - [self assert: a identical: b] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: a) description: 'Error message doesn''t include the expected value'. - self assert: (error includesSubstring: b) description: 'Error message doesn''t include the expected value'].! Item was changed: ----- Method: SUnitTest>>testAssertIdenticalDescription (in category 'tests') ----- testAssertIdenticalDescription + + | a b called | - | a b | a := 'foo'. b := a copy. + + self shouldnt: [self assert: a identical: a description: 'A description42'] raise: TestFailure. + + self should: [self assert: a identical: b description: 'A description42'] raise: TestFailure. + + [self assert: a identical: b description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self assert: a identical: a description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self assert: a identical: b description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! - self should: [self assert: a identical: b description: 'A desciption'] raise: TestFailure. - [self assert: a identical: b description: 'A desciption'] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: 'A desciption') description: 'Error message doesn''t give you the description'].! Item was changed: ----- Method: SUnitTest>>testAssertIdenticalWithEqualObjects (in category 'tests') ----- testAssertIdenticalWithEqualObjects + | a b | a := 'foo'. b := a copy. + self should: [self assert: a identical: b] raise: TestFailure. + + [self assert: a identical: b] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'not identical') + description: 'Error message doesn''t say the two things aren''t identical'].! - [self assert: a identical: b] on: TestFailure do: [:e | |error| - error := e messageText. - self assert: (error includesSubstring: 'not identical') description: 'Error message doesn''t say the two things aren''t identical'].! Item was added: + ----- Method: SUnitTest>>testDenyEquals (in category 'tests') ----- + testDenyEquals + + | a b | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self deny: a equals: b] raise: TestFailure. + + self should: [self deny: a equals: a copy] raise: TestFailure. + + [self deny: a equals: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: a) + description: 'Error message doesn''t include the unexpected value'].! Item was added: + ----- Method: SUnitTest>>testDenyEqualsDescription (in category 'tests') ----- + testDenyEqualsDescription + + | a b called | + a := 'foo'. + b := 'bar'. + + self shouldnt: [self deny: a equals: b description: 'A description42'] raise: TestFailure. + + self should: [self deny: a equals: a copy description: 'A description42'] raise: TestFailure. + + [self deny: a equals: a description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self deny: a equals: b description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self deny: a equals: a description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the generated description'].! Item was added: + ----- Method: SUnitTest>>testDenyIdentical (in category 'tests') ----- + testDenyIdentical + + | a b | + a := 'foo'. + b := 'bar'. + self shouldnt: [self deny: a identical: b] raise: TestFailure. + self should: [self deny: a identical: a] raise: TestFailure. + [self deny: a identical: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: a) + description: 'Error message doesn''t include the unexpected value'].! Item was added: + ----- Method: SUnitTest>>testDenyIdenticalDescription (in category 'tests') ----- + testDenyIdenticalDescription + + | a b called | + a := 'foo'. + b := a copy. + + self shouldnt: [self deny: a identical: b description: 'A description42'] raise: TestFailure. + + self should: [self deny: a identical: a description: 'A description42'] raise: TestFailure. + + [self deny: a identical: a description: 'A description42'] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A description42') + description: 'Error message doesn''t give you the description']. + + called := false. + self shouldnt: [self deny: a identical: b description: [called := true]] raise: TestFailure. + self deny: called description: 'Description block was evaluated prematurely'. + + [self deny: a identical: a description: ['A generated description' asUppercase]] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'A generated description' asUppercase) + description: 'Error message doesn''t give you the description'].! Item was added: + ----- Method: SUnitTest>>testDenyIdenticalWithEqualObjects (in category 'tests') ----- + testDenyIdenticalWithEqualObjects + + | a b | + a := 'foo'. + b := a copy. + self should: [self deny: a identical: a] raise: TestFailure. + [self deny: a identical: a] + on: TestFailure do: [:ex | + self + assert: (ex messageText includesSubstring: 'identical') + description: 'Error message doesn''t say the two things are identical'].! Item was changed: ----- Method: TestCase>>assert:equals: (in category 'asserting') ----- assert: expected equals: actual + ^ self + assert: expected + equals: actual + description: nil - ^self - assert: expected = actual - description: [ self comparingStringBetween: expected and: actual ] ! Item was changed: ----- Method: TestCase>>assert:equals:description: (in category 'asserting') ----- + assert: expected equals: actual description: aStringOrBlock - assert: expected equals: actual description: aString + ^ self - ^self assert: expected = actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetween: expected and: actual)]! - description: [ aString , ': ', (self comparingStringBetween: expected and: actual) ]! Item was changed: ----- Method: TestCase>>assert:identical: (in category 'asserting') ----- assert: expected identical: actual + ^ self + assert: expected + identical: actual + description: nil! - ^self - assert: expected == actual - description: [ self comparingStringBetweenIdentical: expected and: actual ] - ! Item was changed: ----- Method: TestCase>>assert:identical:description: (in category 'asserting') ----- + assert: expected identical: actual description: aStringOrBlock - assert: expected identical: actual description: aString + ^ self - ^self assert: expected == actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetween: expected andIdentical: actual)]! - description: [ aString , ': ', (self comparingStringBetweenIdentical: expected and: actual) ]! Item was changed: ----- Method: TestCase>>comparingStringBetween:and: (in category 'private') ----- comparingStringBetween: expected and: actual + + ^ 'Expected {1} but was {2}.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! - ^ String streamContents: [:stream | - stream - nextPutAll: 'Expected '; - nextPutAll: (expected printStringLimitedTo: 10); - nextPutAll: ' but was '; - nextPutAll: (actual printStringLimitedTo: 10); - nextPutAll: '.' - ]! Item was added: + ----- Method: TestCase>>comparingStringBetween:andIdentical: (in category 'private') ----- + comparingStringBetween: expected andIdentical: actual + + ^ 'Expected {1} and actual {2} are not identical.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was changed: ----- Method: TestCase>>comparingStringBetweenIdentical:and: (in category 'private') ----- comparingStringBetweenIdentical: expected and: actual + + self deprecated. + ^ self comparingStringBetween: expected andIdentical: actual! - ^ 'Expected {1} and actual {2} are not identical.' format: { - expected printStringLimitedTo: 10. - actual printStringLimitedTo: 10. - }! Item was added: + ----- Method: TestCase>>comparingStringBetweenUnexpected:and: (in category 'private') ----- + comparingStringBetweenUnexpected: unexpected and: actual + + ^ 'Did not expect {1} but was {2}.' translated + format: { + unexpected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was added: + ----- Method: TestCase>>comparingStringBetweenUnexpected:andIdentical: (in category 'private') ----- + comparingStringBetweenUnexpected: expected andIdentical: actual + + ^ 'Unexpected {1} and actual {2} are identical.' translated + format: { + expected printStringLimitedTo: 10. + actual printStringLimitedTo: 10 }! Item was changed: ----- Method: TestCase>>deny:equals: (in category 'asserting') ----- deny: unexpected equals: actual + ^ self + deny: unexpected + equals: actual + description: nil! - ^self - deny: unexpected = actual - description: 'Actual equals unexpected' - ! Item was added: + ----- Method: TestCase>>deny:equals:description: (in category 'asserting') ----- + deny: unexpected equals: actual description: aStringOrBlock + + ^ self + deny: unexpected = actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetweenUnexpected: unexpected and: actual)]! Item was added: + ----- Method: TestCase>>deny:identical: (in category 'asserting') ----- + deny: unexpected identical: actual + + ^ self + deny: unexpected + identical: actual + description: nil! Item was added: + ----- Method: TestCase>>deny:identical:description: (in category 'asserting') ----- + deny: unexpected identical: actual description: aStringOrBlock + + ^ self + deny: unexpected == actual + description: [self + description: aStringOrBlock + with: (self comparingStringBetweenUnexpected: unexpected andIdentical: actual)]! Item was added: + ----- Method: TestCase>>description:with: (in category 'private') ----- + description: aStringOrBlock with: reason + + | description | + description := aStringOrBlock value. + ^ description + ifNil: [reason] + ifNotNil: ['{1}: {2}' translated format: {description. reason}]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 8 12:30:30 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 13:30:30 +0100 Subject: [squeak-dev] Bag>>#rehash missing In-Reply-To: References: <5f67a3bfdb9142e7a0ce0833559cc012@hpi.de> Message-ID: How would you compare (in-place) #sort: and #rehash considering their utility? Best, Marcel Am 08.03.2021 11:42:35 schrieb Nicolas Cellier : Le lun. 8 mars 2021 à 08:23, Marcel Taeumel a écrit : > > Hi Nicolas. > > > But on the other hand, I see quite few senders of rehash in the image, > > so I just wonder, are we gonna need it? > > Hmm... I don't think that looking for senders will reveal the actual need for #rehash. Maybe broken bags remain unnoticed? At least a test with proper commentary about this issue might help users to figure out when to use #rehash. In Trunk, there are only a few, short-living examples of bags, which do not suffer from this problem. :-) > > In this particular case, some of our students stumbled upon this issue in a game and did not know how to interpret the effects to figure out what's going on. ... maybe we need some kind of hash-check test (tool) for the entire environment? The biggest issue here is to learn about the correct use of hashing. > > Best, > Marcel > Sure, Bag problems have great chances to get unnoticed because Bags are rarely used in practice. However, it's not a problem of Bag per se, it's a problem of using HashedCollection in general in case when we do not restrict object mutations... My sentiment was that rehash was more a utility method than something needed with regard to standard usage of rehash currently in image. But of course, if you think that it's a useful utility (pleonasm ?), just go. > Am 06.03.2021 23:23:56 schrieb Nicolas Cellier : > > Hi all, > I understand that we can have bags broken by mutation of some > elements, and that rehash could be convenient while debugging. > But on the other hand, I see quite few senders of rehash in the image, > so I just wonder, are we gonna need it? > > I think that private not only covers methods that are really private > and should not be sent by objects of other classes, it also often > means not to be sent in normal circumstances, maybe something closer > to privileged? > > Le sam. 6 mars 2021 à 11:48, Marcel Taeumel a écrit : > > > > Hi Patrick. > > > > +1 on adding #rehash for Bag ... although it technically depends on #contentsClass ? Hmmm... > > > > +0.5 on making #rehash non-private. Hmm.... maybe "initialization" would be a fitting category. Well, definitely not "update" or something like that. Clients should normally not call it, right? > > > > Best, > > Marcel > > > > Am 05.03.2021 20:12:19 schrieb Rein, Patrick : > > > > Hi everyone, > > > > during a recent debugging session I noticed that Bag does not implement #rehash although it is, in essence, a hash-based collection and should therefore probably roughly adhere to the protocol of HashedCollection. Is there a good reason not to have #rehash on Bag? > > > > On a similar note: HashedCollection>>#rehash is in the `private` protocol but has various senders. As even the class comment mentions the usage of #rehash, I would also propose to move it out of the `private` protocol. :) > > > > Best wishes, > > Patrick > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Mon Mar 8 12:33:13 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 8 Mar 2021 06:33:13 -0600 (CST) Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: Message-ID: <1615206793589-0.post@n4.nabble.com> How about this, using valueWithExit again (still long but a bit more readable): | result supplier | supplier := (1 to: 100) readStream. result := OrderedCollection new. [:exitBlock | [supplier atEnd] whileFalse: [ | value | value := supplier next. value even ifTrue: [result add: value squared]. value squared = 2500 ifTrue: [exitBlock value]] ] valueWithExit. result ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Mon Mar 8 14:00:01 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 8 Mar 2021 15:00:01 +0100 Subject: [squeak-dev] Squeak Winter Demos, 2021/03/06,        3 p.m. - 6 p.m. CET, virtual In-Reply-To: References: <17809182705.e47e859d47557.7261929616511810274@zoho.com> Message-ID: Here is something from the demo session to play around with: https://tinyurl.com/squeak-winter-demos-2021-stuff [https://tinyurl.com/squeak-winter-demos-2021-stuff] https://github.com/hpi-swa-lab/babylonian-programming-smalltalk [https://github.com/hpi-swa-lab/babylonian-programming-smalltalk] https://github.com/tom95/sandblocks [https://github.com/tom95/sandblocks] Best, Marcel Am 08.03.2021 08:27:02 schrieb Marcel Taeumel : Hi Timothy, oh no! :-( Yeah, CT, CST, CDT, CET, CEST, ... this can be very confusing. Maybe I should spell it out the next time. I recall a similar issue on a conference last year. Best, Marcel Am 06.03.2021 20:51:29 schrieb gettimothy : well, there is fashionably late and then there is the "order of magnitude late" that happens when i read CET as Central Standard Time . anyway, I was there, just 6 hours late.  Thanks for the invitation (: t ---- On Fri, 05 Mar 2021 07:55:45 -0500 Marcel Taeumel wrote ---- Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! Here are the information for the upcoming "Squeak Winter Demos", which you can also read about on https://squeak.de/news/ [https://squeak.de/news/]. The login for the meeting is as follows: Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) https://uni-potsdam.zoom.us/j/61595939773 [https://uni-potsdam.zoom.us/j/61595939773] Meeting ID: 615 9593 9773 Passcode: 10202428 If you have anymore questions, feel free to contact me under marcel.taeumel at hpi.de [mailto:marcel.taeumel at hpi.de]. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: info at squeak-ev.de [mailto:info at squeak-ev.de] Internet: http://www.squeak.de/squeakev [http://www.squeak.de/squeakev] Am 09.02.2021 17:43:52 schrieb Marcel Taeumel : Dear Squeakers, Smalltalkers, and friends of object-oriented, interactive programming environments! We hope that you are doing well in these difficult times. Please take care of yourself and your peers. We cordially invite you to the “Squeak Winter Demos”, which are organized by the club of German-speaking Squeakers (“Squeak Deutschland e.V.”). We are going to fill that meeting with exciting talks, demos, and discussions. You want to attend or have more questions? Maybe even a proposal for a demo/talk/discussion? Feel free to talk to us so that we can better include your idea in the schedule. Since we want to keep the meeting as flexible as possible, every speaker should plan for about 20 minutes. When? Saturday, March 6, 2021, 3 p.m. to 6 p.m. CET (6 a.m. to 9 a.m. PST) Where? The event will take place as a Zoom call. You need a webcam (maybe with a microphone) and a recent Web browser such as Firefox, Chrome, Edge, or Safari. Alternatively, you can download an app for your operating system via https://zoom.us/download [https://zoom.us/download]. We will share the login data for the virtual meeting here on the day of the event. What will happen? We are currently in the process of planning talks and demos. Feel free to contribute with a short demo or experience report yourself – even on the fly if you want to! We welcome non-members to the meeting. :) Here is a preliminary agenda: * Like the Babylonias: Programming with Examples * Fast and colorful: OpenGL in Squeak * Use the Entire Canvas: Block-based Programming * Spot off, Morph on: Squeak Game Showcase 2020 * It’s Broken! How to debug the debugger =) * Social Media? A Telegram Bot for Squeak … and those who find the time but are not so fluent in German: We always welcome non-German-speaking Squeakers, too! We suppose that you will understand the live demonstrations anyway. :) We will be able to translate technical details or questions into English as well. Stay healthy. Best, Marcel Taeumel --- Squeak Deutschland e.V. c/o Freudenberg, Potsdamer Str. 3a 39114 Magdeburg (GERMANY) E-Mail: info at squeak-ev.de [mailto:info at squeak-ev.de] Internet: http://www.squeak.de/squeakev [http://www.squeak.de/squeakev] -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Mon Mar 8 14:46:39 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 8 Mar 2021 14:46:39 0000 Subject: [squeak-dev] The Trunk: Collections-nice.930.mcz Message-ID: Nicolas Cellier uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-nice.930.mcz ==================== Summary ==================== Name: Collections-nice.930 Author: nice Time: 8 March 2021, 3:46:35.811868 pm UUID: 923d86a7-1d60-4d7f-975a-c20e365efc5a Ancestors: Collections-nice.929 Fix my horrible bug before it gets noticed **Blush** I stupidely tested against Array (good) with #yourself as the collect: block (bad idea!) =============== Diff against Collections-nice.929 =============== Item was changed: ----- Method: LimitedPrecisionInterval>>collect: (in category 'enumerating') ----- collect: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Collect the resulting values into a collection like the receiver. Answer the new collection. Implementation notes: see do: for an explanation on loop detail" | result | result := self species new: self size. 1 to: result size do: [:i | "(self at: i) is inlined here to avoid repeated bound checking" + result at: i put: (aBlock value: i - 1 * step + start)]. - result at: i put: i - 1 * step + start]. ^ result! From stes at telenet.be Mon Mar 8 18:36:29 2021 From: stes at telenet.be (stes@PANDORA.BE) Date: Mon, 8 Mar 2021 19:36:29 +0100 (CET) Subject: [squeak-dev] Squeak Winter Demos, 2021/03/06, 3 p.m. - 6 p.m. CET, virtual Message-ID: <1672426522.21384552.1615228589848.JavaMail.zimbra@telenet.be> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Excellent initiative; all of the talks were interesting. Thanks for setting this up. Regards, David Stes -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBCAAGBQJgRm3mAAoJEAwpOKXMq1MaQp0IALgkn8XlLHk8EYs0C9M87gh9 tFVJlh5/y/wyEzEZ4/JV8StLX6BZbOfYl5VuUSVx821g7a2UTp/5Y1L8M0Or/tVP mbf9+E4gJGz5w+Uj9ZNJxkR3SYYourns4zGINpOKD5090X+S14OC6RLH2ri1IF16 OmWC9zX69hTFc0g6J7xpL0Tf4qxBW3Pazbm8d7vwT83Hh0jwShL38QijsfVCLo8u 3OTSpsAAUFjoK40mwteC6q0uU0orRcfY3m6ckdzpXEM5zmJLY77Ftee1pmrAyAvA +8GFPNsBWp3zKXyNyv1nhs9FwoYJr9/Pu8ZMkIUIPlW9qHIh1RoK9PTHMZ9LVK8= =PlJ2 -----END PGP SIGNATURE----- From christoph.thiede at student.hpi.uni-potsdam.de Mon Mar 8 19:21:36 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Mon, 8 Mar 2021 13:21:36 -0600 (CST) Subject: [squeak-dev] Tackling Context>>#runUntilErrorReturnFrom: (was: BUG/REGRESSION while debugging Generator >> #nextPut:) In-Reply-To: <25a67367ce4f4ee68d0509659cb10c72@student.hpi.uni-potsdam.de> References: <9ed2db8e40684297b83d98e311e76a4b@student.hpi.uni-potsdam.de> <25a67367ce4f4ee68d0509659cb10c72@student.hpi.uni-potsdam.de> Message-ID: <1615231296272-0.post@n4.nabble.com> Hi all, hi Eliot, hi Marcel,it's been a long time, but this issue still exists and I have been making a lot of thoughts about it while investigating this and other issues. Marcel and I will soon release a fix for the infinite debugger chains in general, but this issue is a separate one.<short recap>Under certain circumstances, running a single step in a debugger (mostly via the Over button) abandons the current UI process and proceeds the debugged process in its place. This is caused by an *insane and extremely powerful hack in Context>>#runUntilErrorReturnFrom:,* which hacks the context to be simulated into the currently running process. This can speed up debugging by around factor 1000. To ensure that the execution returns to the debugging process, two guard contexts are installed on top of the respective context.Unfortunately, if the debugged process contains any piece of *context metaprogramming,* i.e. by implementing coroutine logic with Context>>#swapSender:, or by performing #jump​s, this can uninstall the guard contexts or make them unreachable, eventually *causing the debugged process to successfully hijack the debugging process and never return control back to it.*</short recap>After all, I think *there is no viable alternative to explicitly informing the debugger about such acts of context metaprogramming.* For this reason, I have set up a working and unpolished prototype in my image, which, in a nutshell, applies the following changes to Context:1. In #jump and #swapSender:, insert a send {self informDebuggerAboutContextSwitchTo: coroutine} right before installing the new sender.2. #informDebuggerAboutContextSwitchTo: searches the sender stack for an UnhandledError handler that was installed by #runUntilErrorOrReturnFrom:. If it finds one, it checks whether this context would still be available after the context switch. (If yes, nothing is done, otherwise stepping over complex messages such as {self systemNavigation allCallsOn: #foo} would become really messy.) If no, an UnhandledError is signaled to abort the #runUntilErrorOrReturnFrom: execution prematurely.You can find the details in the attached changeset, but IMO implementation details are less relevant for the current discussion than a general understanding of the problem and the solution approach.Here are some questions for you:1. *Would you agree that is the right approach to the problem* because there are no alternatives?2. Now it's getting indeed a bit more technical: At the moment, #findNextRunUntilErrorOrReturnFromCalleeContextUpTo: in my implementation (horrible name, I know ...) manually traverses the chain of #nextHandlerContext​s to search for an UnhandledError handler of interest. However, I don't really like this approach because a) it creates a *high coupling to the #runUntilErrorOrReturnFrom: implementation* (well, on the other hand, both methods resist in the same class ...) and b) it might introduce a *noticeable performance drop* (premature benchmarks have suggested an overhead of 5%-25% depending on the task).I need to build better measures, but a question in general: *Are we willing to accept this performance drop in order to regain correctness?* (In my opinion, we should be willing, it is only used for debugging and "still fast enough for our neurons" :-))An alternative to manually scanning all handler contexts could be to introduce a new exception for this (maybe ContextSwitchNotification) and let the VM do all the work. Or am I overrating "The Great VM" in this regard and things won't be able to become faster than #handleSignal: at all? For such a low-level, performance-critical decision, I think design questions should be secondary.Do you have some thoughts and opinions about this?*I am looking forward to your feedback!* Let's get this problem solved, too, definitively before the next release! :-)Best,Christoph runUntilErrorOrReturnFrom.cs ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Mon Mar 8 19:24:24 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Mon, 8 Mar 2021 19:24:24 +0000 Subject: [squeak-dev] Tackling Context>>#runUntilErrorReturnFrom: (was: BUG/REGRESSION while debugging Generator >> #nextPut:) In-Reply-To: <1615231296272-0.post@n4.nabble.com> References: <9ed2db8e40684297b83d98e311e76a4b@student.hpi.uni-potsdam.de> <25a67367ce4f4ee68d0509659cb10c72@student.hpi.uni-potsdam.de>, <1615231296272-0.post@n4.nabble.com> Message-ID: The formatting of this message was unacceptable. I'm attaching it in a reformated style ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Thiede, Christoph Gesendet: Montag, 8. März 2021 20:21 Uhr An: squeak-dev at lists.squeakfoundation.org Betreff: [squeak-dev] Tackling Context>>#runUntilErrorReturnFrom: (was: BUG/REGRESSION while debugging Generator >> #nextPut:) Hi all, hi Eliot, hi Marcel, it's been a long time, but this issue still exists and I have been making a lot of thoughts about it while investigating this and other issues. Marcel and I will soon release a fix for the infinite debugger chains in general, but this issue is a separate one. Under certain circumstances, running a single step in a debugger (mostly via the Over button) abandons the current UI process and proceeds the debugged process in its place. This is caused by an insane and extremely powerful hack in Context>>#runUntilErrorReturnFrom:, which hacks the context to be simulated into the currently running process. This can speed up debugging by around factor 1000. To ensure that the execution returns to the debugging process, two guard contexts are installed on top of the respective context. Unfortunately, if the debugged process contains any piece of context metaprogramming, i.e. by implementing coroutine logic with Context>>#swapSender:, or by performing #jumps, this can uninstall the guard contexts or make them unreachable, eventually causing the debugged process to successfully hijack the debugging process and never return control back to it. After all, I think there is no viable alternative to explicitly informing the debugger about such acts of context metaprogramming. For this reason, I have set up a working and unpolished prototype in my image, which, in a nutshell, applies the following changes to Context: 1. In #jump and #swapSender:, insert a send {self informDebuggerAboutContextSwitchTo: coroutine} right before installing the new sender. 2. #informDebuggerAboutContextSwitchTo: searches the sender stack for an UnhandledError handler that was installed by #runUntilErrorOrReturnFrom:. If it finds one, it checks whether this context would still be available after the context switch. (If yes, nothing is done, otherwise stepping over complex messages such as {self systemNavigation allCallsOn: #foo} would become really messy.) If no, an UnhandledError is signaled to abort the #runUntilErrorOrReturnFrom: execution prematurely. You can find the details in the attached changeset, but IMO implementation details are less relevant for the current discussion than a general understanding of the problem and the solution approach. Here are some questions for you: 1. Would you agree that is the right approach to the problem because there are no alternatives? 2. Now it's getting indeed a bit more technical: At the moment, #findNextRunUntilErrorOrReturnFromCalleeContextUpTo: in my implementation (horrible name, I know ...) manually traverses the chain of #nextHandlerContexts to search for an UnhandledError handler of interest. However, I don't really like this approach because a) it creates a high coupling to the #runUntilErrorOrReturnFrom: implementation (well, on the other hand, both methods resist in the same class ...) and b) it might introduce a noticeable performance drop (premature benchmarks have suggested an overhead of 5%-25% depending on the task). I need to build better measures, but a question in general: Are we willing to accept this performance drop in order to regain correctness? (In my opinion, we should be willing, it is only used for debugging and "still fast enough for our neurons" :-)) An alternative to manually scanning all handler contexts could be to introduce a new exception for this (maybe ContextSwitchNotification) and let the VM do all the work. Or am I overrating "The Great VM" in this regard and things won't be able to become faster than #handleSignal: at all? For such a low-level, performance-critical decision, I think design questions should be secondary. Do you have some thoughts and opinions about this I am looking forward to your feedback! Let's get this problem solved, too, definitively before the next release! :-) Best, Christoph runUntilErrorOrReturnFrom.cs Carpe Squeak! ________________________________ Sent from the Squeak - Dev mailing list archive at Nabble.com. -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: runUntilErrorOrReturnFrom.4.cs URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Mon Mar 8 20:08:57 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Mon, 8 Mar 2021 20:08:57 +0000 Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts Message-ID: Hi all, besides my proposed solution approach for the never-returning sends to Context>>#runUntilErrorReturnFrom: [1], I recently stumbled upon another problem with context manipulation connected to #runUntilErrorReturnFrom:. But I think the cause is a different one and this one brings up a more general design discussion. Let me explain: The bug itself is pretty simple to reproduce: 1. Do it: [self error] ensure: [^2] 2. Abandon the Error debugger 3. Do it: self error Expected behavior: A second error debugger is shown Actual behavior: An unwind error (Unwind error during termination) is shown! Here's an explanation: If you inspect your UI process after step 2, you will see that two guard contexts (BlockClosure>>on:do: and BlockClosure>>ensure:) are installed right before [] in BlockClosure>>newProcess on the bottom of the sender stack. These contexts have been created by #runUntilErrorOrReturnFrom: as part of the context popping-down performed by Process>>#terminate when abandoning the debugger. Normally, they would have been removed again after unwinding all contexts from the process (and the UI process would have been terminated and been replaced by a new one, see #spawnNewProcessIfThisIsUI:). But because our "ensure: [^2]" has stopped the unwinding, #runUntilErrorOrReturnFrom: and senders are still alive and waiting for the unwinding to complete while the UI process is continuing its everyday world cycles. When the next error is raised at any time later, the UnhandledError guard gets invoked and the signaler context is returned back from Process>>#popTo:, and Process>>#terminate complains that the unwinding has not been successful. So far about the problem, here are some thoughts and questions: 1. Should it be a legal operation at all to return from an unwind context? (I think it should, because a) it works fine unless Process>>#terminate gets involved, and b) it is a powerful instrument for certain control flows that need to ignore all exceptions.) (1.1 If you think we should criminalize this operation, should we make efforts to exclude this behavior in #aboutToReturn:through: and other places? I fear this could become quite complex ...) 2. I'm attaching a small changeset to fix this issue by decriminalizing unwind errors and continuing the execution (with the new error) instead of showing an unwind error. It's a small patch of three lines that works surprisingly well for my use case, but I'm not sure whether there could be any other justified reasons for showing an unwind error. Do you know some other relevant reasons for unwinding errors? 3. Also, the solution approach begs a new question to me: Should the #terminate send indeed freeze for potentially hours of image time or millions of bytecodes, or are we required to find another way for this? I hope for the first because I really can't imagine an elegant alternative at the moment. Looking forward to your thoughts! :-) CC'ing Jaromir because you're working on the same method at the moment. Afaik you are only reworking the definition of #isTerminated, but probably you can share some interesting insights on this issue, too. :-) Best, Christoph (PS: This message, as my previous one, has become quite long, I know this. General suggestions for reasonable shortening of my texts will be appreciated, I'm always trying to waste as little as possible of your time ... :-)) [1] http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-nextPut-tp5108125p5127567.html -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: unwind-errors.1.cs URL: From m at jaromir.net Mon Mar 8 20:38:51 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 8 Mar 2021 14:38:51 -0600 (CST) Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: Message-ID: <1615235931986-0.post@n4.nabble.com> > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners > collect: [:morph | morph color] > until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100) collect: [:x | x squared] where: [:x | x even] until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock | result supplier | supplier := self readStream. result := {} writeStream. [[supplier atEnd] whileFalse: [ | val | val := supplier next. (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)]. (untilBlock value: val) ifTrue: [^result contents]] ] value. ^result contents collect: colBlock until: untilBlock ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From nicolas.cellier.aka.nice at gmail.com Mon Mar 8 22:33:13 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Mon, 8 Mar 2021 23:33:13 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <1615235931986-0.post@n4.nabble.com> References: <1615235931986-0.post@n4.nabble.com> Message-ID: I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > > I am looking for something like #collect:until: or #upToSatisfying:. I do > want the stop element to be included here, not sure about the general case. > > > > aButton withAllOwners > > collect: [:morph | morph color] > > until: [:morph | morph isSystemWindow]. > > > > Hi again, ahh so you're actually looking for a generalized collect for any > SequencableCollection or Stream :) Like this? > > (1 to: 100) > collect: [:x | x squared] > where: [:x | x even] > until: [:x | x squared = 2500] > > > collect: collectBlock where: whereBlock until: untilBlock > > | result supplier | > supplier := self readStream. > result := {} writeStream. > [[supplier atEnd] > whileFalse: [ | val | > val := supplier next. > (whereBlock value: val) ifTrue: [result nextPut: > (collectBlock value: > val)]. > (untilBlock value: val) ifTrue: [^result contents]] > ] value. > ^result contents > > collect: colBlock until: untilBlock > > ^self collect: colBlock where: [:each | true] until: untilBlock > > or even: > > collect: colBlock > > ^self collect: colBlock until: [:each | true] > > > > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From asqueaker at gmail.com Tue Mar 9 04:53:10 2021 From: asqueaker at gmail.com (Chris Muller) Date: Mon, 8 Mar 2021 22:53:10 -0600 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <20210306150521.GA34636@shell.msen.com> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> Message-ID: > > My expectation would be that #second, #minute, #hour etc would > be syntactic sugar. And I certainly would not expect "5 second" > to mean one second duration. > > I note that we have several methods like this (second, minute, hour...) > and they have Brent Pinkney's (brp) initials since 2004. I don't know > if anyone depends on that existing behavior. > That's correct. Brent adopted those methods from my MaTimeObjects package (which is still installable from SqueakMap), although in my version it didn't even account for the sign, it was always just ^ 1 second, regardless of the receiver. I agree they should just be synonyms. > Off topic, but there are other problems with these duration methods. > They are defined in Number but round the duration magnitudes to > whole seconds. Where do you see that? I just tried "1.5 hours" and it worked... > And durations for 1 day or 1 week are undefinable > due to daylight savings transitions and occasional leap seconds. True, from a literal sense, but by that assessment we would have similar "problems" with ChronologyConstants' DaysInMonth, MicrosecondsInDay, OneDay, SecondsInDay, SecondsInHour, and SecondsInMinute. All are useful, nonetheless. - Chris -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicolas.cellier.aka.nice at gmail.com Tue Mar 9 07:07:06 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Tue, 9 Mar 2021 08:07:06 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> Message-ID: Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier < nicolas.cellier.aka.nice at gmail.com> a écrit : > I like that, it's beginning to be expressive, even better than clojure. > However, i think that clojure offers composable predicates thanks to > lazyness... like Xtreams. > > Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > >> > I am looking for something like #collect:until: or #upToSatisfying:. I >> do >> want the stop element to be included here, not sure about the general >> case. >> > >> > aButton withAllOwners >> > collect: [:morph | morph color] >> > until: [:morph | morph isSystemWindow]. >> > >> >> Hi again, ahh so you're actually looking for a generalized collect for any >> SequencableCollection or Stream :) Like this? >> >> (1 to: 100) >> collect: [:x | x squared] >> where: [:x | x even] >> until: [:x | x squared = 2500] >> >> >> collect: collectBlock where: whereBlock until: untilBlock >> >> | result supplier | >> supplier := self readStream. >> result := {} writeStream. >> [[supplier atEnd] >> whileFalse: [ | val | >> val := supplier next. >> (whereBlock value: val) ifTrue: [result nextPut: >> (collectBlock value: >> val)]. >> (untilBlock value: val) ifTrue: [^result contents]] >> ] value. >> ^result contents >> >> collect: colBlock until: untilBlock >> >> ^self collect: colBlock where: [:each | true] until: untilBlock >> >> or even: >> >> collect: colBlock >> >> ^self collect: colBlock until: [:each | true] >> >> >> >> >> ----- >> ^[^ Jaromir >> -- >> Sent from: http://forum.world.st/Squeak-Dev-f45488.html >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 08:40:38 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 09:40:38 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> Message-ID: Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result |    aButton withAllOwners       do: [:morph | result nextPut: morph color]       upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners >    collect: [:morph | morph color] >    until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100)         collect: [:x | x squared]         where: [:x | x even]         until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock         | result supplier |         supplier := self readStream.         result := {} writeStream.         [[supplier atEnd]             whileFalse: [ | val |               val := supplier next.               (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)].               (untilBlock value: val) ifTrue: [^result contents]]         ] value.         ^result contents collect: colBlock until: untilBlock         ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock         ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html [http://forum.world.st/Squeak-Dev-f45488.html] -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 09:50:09 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 10:50:09 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: Message-ID: Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers)   Magnitude     Number Math-Quantity   Integer (+ subclasses)   Fraction   ScaledDecimal Math-Analysis   Complex   Float (+ subclasses)   Quaternion Math-Geometry   Point   Line   Rectangle   Polygon   Path Math-Collections   Vector2 (from 3DTransform, CroquetGL, etc.)   Vector3   Vector4   Matrix2x3   Matrix4x4   VectorArray   ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Tue Mar 9 09:54:02 2021 From: m at jaromir.net (Jaromir Matas) Date: Tue, 9 Mar 2021 03:54:02 -0600 (CST) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: References: Message-ID: <1615283642086-0.post@n4.nabble.com> Hi Christopher, I've just been wondering what that part of #terminate was for... Thanks for the answer :) I tried a recursive version of your example and it behaves even worse: [self error: 'x1'] ensure: [[self error: 'x2'] ensure: [[[[self error: 'x3'] ensure: [^2]] ensure: [^2]] ensure: [^2]]] And this one's bad too - hit Abandon and you get the unwind error right away: [self error] ensure: [1/0] After your fix/workaround they miraculously seem to behave again :) A question: why not simply `ctxt restart`? Without assigning to suspendedContext. Like this: #terminate "... lots of code" ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: >>> [ctxt restart. "self debug: ctxt title: 'Unwind error during termination'"]. "Set the context to its endPC for the benefit of isTerminated." ctxt pc: ctxt endPC] And finally, I noticed #valueUninterruptably uses return from an unwind context as well and it doesn't seem to function properly due to the bug (ok after your fix): [1/0] valueUninterruptably First doit generates ZeroDivide, hit Abandon and the next doit shows unwind error but Proceed will just end the process (I'd expect another ZeroDivide - am I right?) #valueUninterruptably "Prevent remote returns from escaping the sender. Even attempts to terminate (unwind) this process will be halted and the process will resume here. A terminate message is needed for every one of these in the sender chain to get the entire process unwound." ^ self ifCurtailed: [^ self] Besides #isTerminated I've been trying to refactor #terminate and #newProcess to avoid 'cannot return' errors and unify different kinds of termination (active process termination and suspended process termination). I've sent it to the Inbox for discussion - see here: http://forum.world.st/The-Inbox-Kernel-jar-1380-mcz-td5127524.html Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Tue Mar 9 10:40:22 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 9 Mar 2021 10:40:22 0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1380.mcz Message-ID: Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1380.mcz ==================== Summary ==================== Name: Kernel-mt.1380 Author: mt Time: 9 March 2021, 11:40:18.855529 am UUID: cef64cd0-d892-584e-8bce-6f5dac0202fc Ancestors: Kernel-eem.1379 Make sure that special object no. 38 is FullBlockClosure. See discussion at http://forum.world.st/Smalltalk-specialObjectsArray-at-38-tp5125148p5125164.html =============== Diff against Kernel-eem.1379 =============== Item was added: + ----- Method: FullBlockClosure class>>initialize (in category 'class initialization') ----- + initialize + "Also see SmalltalkImage >> #recreateSpecialObjectsArray." + + (Smalltalk specialObjectsArray at: 38) + ifNil: [Smalltalk specialObjectsArray at: 38 put: self].! From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 11:40:50 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 11:40:50 +0000 Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615283642086-0.post@n4.nabble.com> References: , <1615283642086-0.post@n4.nabble.com> Message-ID: <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> Hi Jaromir, thanks a lot for your answer! Great to hear that you have found some other examples that would benefit from my patch as well. :-) > A question: why not simply `ctxt restart`? Without assigning to suspendedContext. Like this: > > #terminate > "... lots of code" > ctxt := self popTo: suspendedContext bottomContext. > ctxt == suspendedContext bottomContext ifFalse: > >>> [ctxt restart. > "self debug: ctxt title: 'Unwind error during termination'"]. > "Set the context to its endPC for the benefit of isTerminated." > ctxt pc: ctxt endPC] The "ctxt restart" was necessary to have the raised exception handled again after it has been absorbed by #runUntilErrorOrReturnFrom:. I'm not sure about the exact semantics of suspendedContext, but shouldn't it always point to the latest context frame unless the process is running? Should we rather set suspendedContext to nil here? That's another point I find questionary about my changeset - if the process refuses to terminate, it will be resumed again, even if it has been suspended before. Can or should we change that or is it already the most logical way (because every "unwinding" essentially means to "resume" the process anyway)? Anyway, I think the method return after restarting the context is necessary because otherwise, its pc will be manipulated which we don't want unless the process has really been terminated. #valueUninterruptably is also an interesting example. But this should also have been fixed using my proposal, shouldn't it? :-) > Besides #isTerminated I've been trying to refactor #terminate and #newProcess to avoid 'cannot return' errors and unify different kinds of termination (active process termination and suspended process termination). Nice work! Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Dienstag, 9. März 2021 10:54:02 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts Hi Christopher, I've just been wondering what that part of #terminate was for... Thanks for the answer :) I tried a recursive version of your example and it behaves even worse: [self error: 'x1'] ensure: [[self error: 'x2'] ensure: [[[[self error: 'x3'] ensure: [^2]] ensure: [^2]] ensure: [^2]]] And this one's bad too - hit Abandon and you get the unwind error right away: [self error] ensure: [1/0] After your fix/workaround they miraculously seem to behave again :) A question: why not simply `ctxt restart`? Without assigning to suspendedContext. Like this: #terminate "... lots of code" ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: >>> [ctxt restart. "self debug: ctxt title: 'Unwind error during termination'"]. "Set the context to its endPC for the benefit of isTerminated." ctxt pc: ctxt endPC] And finally, I noticed #valueUninterruptably uses return from an unwind context as well and it doesn't seem to function properly due to the bug (ok after your fix): [1/0] valueUninterruptably First doit generates ZeroDivide, hit Abandon and the next doit shows unwind error but Proceed will just end the process (I'd expect another ZeroDivide - am I right?) #valueUninterruptably "Prevent remote returns from escaping the sender. Even attempts to terminate (unwind) this process will be halted and the process will resume here. A terminate message is needed for every one of these in the sender chain to get the entire process unwound." ^ self ifCurtailed: [^ self] Besides #isTerminated I've been trying to refactor #terminate and #newProcess to avoid 'cannot return' errors and unify different kinds of termination (active process termination and suspended process termination). I've sent it to the Inbox for discussion - see here: http://forum.world.st/The-Inbox-Kernel-jar-1380-mcz-td5127524.html Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 11:42:29 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 11:42:29 +0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1380.mcz In-Reply-To: References: Message-ID: Hi Marcel, why do we need a redundant #initialize method for this? Wouldn't it have been enough to trigger #recreateSpecialObjectsArray in a postscript? Duplication hurts :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 9. März 2021 11:40:22 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-mt.1380.mcz Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1380.mcz ==================== Summary ==================== Name: Kernel-mt.1380 Author: mt Time: 9 March 2021, 11:40:18.855529 am UUID: cef64cd0-d892-584e-8bce-6f5dac0202fc Ancestors: Kernel-eem.1379 Make sure that special object no. 38 is FullBlockClosure. See discussion at http://forum.world.st/Smalltalk-specialObjectsArray-at-38-tp5125148p5125164.html =============== Diff against Kernel-eem.1379 =============== Item was added: + ----- Method: FullBlockClosure class>>initialize (in category 'class initialization') ----- + initialize + "Also see SmalltalkImage >> #recreateSpecialObjectsArray." + + (Smalltalk specialObjectsArray at: 38) + ifNil: [Smalltalk specialObjectsArray at: 38 put: self].! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 11:47:11 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 12:47:11 +0100 Subject: [squeak-dev] The Trunk: Kernel-mt.1380.mcz In-Reply-To: References: Message-ID: Hi Christoph. > Duplication hurts :-) Now think again about modularity and global state. ;-) Take the slot for "Alien" as an example, which I replaced in "FFI-Callbacks". Projects are free to switch between compatible classes as the VM will happily produce the new instances. While this may not be true for all slots in the special-objects array, it is still true for many of them. So, #recreateSpecialObjectsArray may be the actual issue here.    Best, Marcel Am 09.03.2021 12:42:36 schrieb Thiede, Christoph : Hi Marcel, why do we need a redundant #initialize method for this? Wouldn't it have been enough to trigger #recreateSpecialObjectsArray in a postscript? Duplication hurts :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 9. März 2021 11:40:22 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-mt.1380.mcz   Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1380.mcz [http://source.squeak.org/trunk/Kernel-mt.1380.mcz] ==================== Summary ==================== Name: Kernel-mt.1380 Author: mt Time: 9 March 2021, 11:40:18.855529 am UUID: cef64cd0-d892-584e-8bce-6f5dac0202fc Ancestors: Kernel-eem.1379 Make sure that special object no. 38 is FullBlockClosure. See discussion at http://forum.world.st/Smalltalk-specialObjectsArray-at-38-tp5125148p5125164.html [http://forum.world.st/Smalltalk-specialObjectsArray-at-38-tp5125148p5125164.html] =============== Diff against Kernel-eem.1379 =============== Item was added: + ----- Method: FullBlockClosure class>>initialize (in category 'class initialization') ----- + initialize +        "Also see SmalltalkImage >> #recreateSpecialObjectsArray." +        +        (Smalltalk specialObjectsArray at: 38) +                ifNil: [Smalltalk specialObjectsArray at: 38 put: self].! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 11:56:04 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 11:56:04 +0000 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: , Message-ID: Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers) Magnitude Number Math-Quantity Integer (+ subclasses) Fraction ScaledDecimal Math-Analysis Complex Float (+ subclasses) Quaternion Math-Geometry Point Line Rectangle Polygon Path Math-Collections Vector2 (from 3DTransform, CroquetGL, etc.) Vector3 Vector4 Matrix2x3 Matrix4x4 VectorArray ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 12:02:27 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 12:02:27 +0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1380.mcz In-Reply-To: References: , Message-ID: <61a1aff6528445ceb7c98b81d7dfaebc@student.hpi.uni-potsdam.de> Hi Marcel, that's a fair point. :-) How can we get rid of Alien in #recreateSpecialObjects? Would it be okay to move it into something like "Alien initialize"? Or should #recreateSpecialObjects provide hooks/arguments to keep control of this central array? The method comment states that external packages should use addGCRoot() instead. Why doesn't Alien do so? Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 12:47:11 An: squeak-dev Betreff: Re: [squeak-dev] The Trunk: Kernel-mt.1380.mcz Hi Christoph. > Duplication hurts :-) Now think again about modularity and global state. ;-) Take the slot for "Alien" as an example, which I replaced in "FFI-Callbacks". Projects are free to switch between compatible classes as the VM will happily produce the new instances. While this may not be true for all slots in the special-objects array, it is still true for many of them. So, #recreateSpecialObjectsArray may be the actual issue here. Best, Marcel Am 09.03.2021 12:42:36 schrieb Thiede, Christoph : Hi Marcel, why do we need a redundant #initialize method for this? Wouldn't it have been enough to trigger #recreateSpecialObjectsArray in a postscript? Duplication hurts :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 9. März 2021 11:40:22 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-mt.1380.mcz Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1380.mcz ==================== Summary ==================== Name: Kernel-mt.1380 Author: mt Time: 9 March 2021, 11:40:18.855529 am UUID: cef64cd0-d892-584e-8bce-6f5dac0202fc Ancestors: Kernel-eem.1379 Make sure that special object no. 38 is FullBlockClosure. See discussion at http://forum.world.st/Smalltalk-specialObjectsArray-at-38-tp5125148p5125164.html =============== Diff against Kernel-eem.1379 =============== Item was added: + ----- Method: FullBlockClosure class>>initialize (in category 'class initialization') ----- + initialize + "Also see SmalltalkImage >> #recreateSpecialObjectsArray." + + (Smalltalk specialObjectsArray at: 38) + ifNil: [Smalltalk specialObjectsArray at: 38 put: self].! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 12:10:29 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 12:10:29 +0000 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: , , Message-ID: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 9. März 2021 12:56:04 An: squeak-dev Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers) Magnitude Number Math-Quantity Integer (+ subclasses) Fraction ScaledDecimal Math-Analysis Complex Float (+ subclasses) Quaternion Math-Geometry Point Line Rectangle Polygon Path Math-Collections Vector2 (from 3DTransform, CroquetGL, etc.) Vector3 Vector4 Matrix2x3 Matrix4x4 VectorArray ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 12:23:06 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 12:23:06 +0000 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> , Message-ID: Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result | aButton withAllOwners do: [:morph | result nextPut: morph color] upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier > a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas > a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners > collect: [:morph | morph color] > until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100) collect: [:x | x squared] where: [:x | x even] until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock | result supplier | supplier := self readStream. result := {} writeStream. [[supplier atEnd] whileFalse: [ | val | val := supplier next. (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)]. (untilBlock value: val) ifTrue: [^result contents]] ] value. ^result contents collect: colBlock until: untilBlock ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 9 12:33:42 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 9 Mar 2021 12:33:42 0000 Subject: [squeak-dev] The Inbox: ST80-mt.265.mcz Message-ID: A new version of ST80 was added to project The Inbox: http://source.squeak.org/inbox/ST80-mt.265.mcz ==================== Summary ==================== Name: ST80-mt.265 Author: mt Time: 9 March 2021, 1:33:39.525921 pm UUID: 1b02e796-d790-b34d-9f4f-dd406f43e130 Ancestors: ST80-mt.264 Free the names Path, Arc, Circle, Line, Spline to be used in a prospective Math package. =============== Diff against ST80-mt.264 =============== Item was removed: - Path subclass: #Arc - instanceVariableNames: 'quadrant radius center' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Arc commentStamp: '' prior: 0! - Arcs are an unusual implementation of splines due to Ted Kaehler. Imagine two lines that meet at a corner. Now imagine two moving points; one moves from the corner to the end on one line, the other moves from the end of the other line in to the corner. Now imagine a series of lines drawn between those moving points at each step along the way (they form a sort of spider web pattern). By connecting segments of the intersecting lines, a smooth curve is achieved that is tangent to both of the original lines. Voila.! Item was removed: - ----- Method: Arc class>>example (in category 'examples') ----- - example - "Click the button somewhere on the screen. The designated point will - be the center of an Arc with radius 50 in the 4th quadrant." - - | anArc aForm | - aForm := Form extent: 1 @ 30. "make a long thin Form for display" - aForm fillBlack. "turn it black" - anArc := Arc new. - anArc form: aForm. "set the form for display" - anArc radius: 50.0. - anArc center: Sensor waitButton. - anArc quadrant: 4. - anArc displayOn: Display. - Sensor waitButton - - "Arc example"! Item was removed: - ----- Method: Arc>>center (in category 'accessing') ----- - center - "Answer the point at the center of the receiver." - - ^center! Item was removed: - ----- Method: Arc>>center: (in category 'accessing') ----- - center: aPoint - "Set aPoint to be the receiver's center." - - center := aPoint! Item was removed: - ----- Method: Arc>>center:radius: (in category 'accessing') ----- - center: aPoint radius: anInteger - "The receiver is defined by a point at the center and a radius. The - quadrant is not reset." - - center := aPoint. - radius := anInteger! Item was removed: - ----- Method: Arc>>center:radius:quadrant: (in category 'accessing') ----- - center: aPoint radius: anInteger quadrant: section - "Set the receiver's quadrant to be the argument, section. The size of the - receiver is defined by the center and its radius." - - center := aPoint. - radius := anInteger. - quadrant := section! Item was removed: - ----- Method: Arc>>computeBoundingBox (in category 'display box access') ----- - computeBoundingBox - | aRectangle aPoint | - aRectangle := center - radius + form offset extent: form extent + (radius * 2) asPoint. - aPoint := center + form extent. - quadrant = 1 ifTrue: [^ aRectangle encompass: center x @ aPoint y]. - quadrant = 2 ifTrue: [^ aRectangle encompass: aPoint x @ aPoint y]. - quadrant = 3 ifTrue: [^ aRectangle encompass: aPoint x @ center y]. - quadrant = 4 ifTrue: [^ aRectangle encompass: center x @ center y]! Item was removed: - ----- Method: Arc>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - - | nSegments line angle sin cos xn yn | - nSegments := 12.0. - line := Line new. - line form: self form. - angle := (90.0 / nSegments) degreesToRadians. - sin := angle sin. - cos := angle cos. - quadrant = 1 - ifTrue: - [xn := radius asFloat. - yn := 0.0]. - quadrant = 2 - ifTrue: - [xn := 0.0. - yn := 0.0 - radius asFloat]. - quadrant = 3 - ifTrue: - [xn := 0.0 - radius asFloat. - yn := 0.0]. - quadrant = 4 - ifTrue: - [xn := 0.0. - yn := radius asFloat]. - nSegments asInteger - timesRepeat: - [ | xn1 yn1 | - xn1 := xn * cos + (yn * sin). - yn1 := yn * cos - (xn * sin). - line beginPoint: center + (xn asInteger @ yn asInteger). - line endPoint: center + (xn1 asInteger @ yn1 asInteger). - line - displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm. - xn := xn1. - yn := yn1]! Item was removed: - ----- Method: Arc>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - | newArc tempCenter | - newArc := Arc new. - tempCenter := aTransformation applyTo: self center. - newArc center: tempCenter x asInteger @ tempCenter y asInteger. - newArc quadrant: self quadrant. - newArc radius: (self radius * aTransformation scale x) asInteger. - newArc form: self form. - newArc - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - ----- Method: Arc>>quadrant (in category 'accessing') ----- - quadrant - "Answer the part of the circle represented by the receiver." - ^quadrant! Item was removed: - ----- Method: Arc>>quadrant: (in category 'accessing') ----- - quadrant: section - "Set the part of the circle represented by the receiver to be the argument, - section." - - quadrant := section! Item was removed: - ----- Method: Arc>>radius (in category 'accessing') ----- - radius - "Answer the receiver's radius." - - ^radius! Item was removed: - ----- Method: Arc>>radius: (in category 'accessing') ----- - radius: anInteger - "Set the receiver's radius to be the argument, anInteger." - - radius := anInteger! Item was removed: - Arc subclass: #Circle - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Circle commentStamp: '' prior: 0! - I represent a full circle. I am made from four Arcs.! Item was removed: - ----- Method: Circle class>>exampleOne (in category 'examples') ----- - exampleOne - "Click any button somewhere on the screen. The point will be the center - of the circcle of radius 150." - - | aCircle aForm | - aForm := Form extent: 1 at 30. - aForm fillBlack. - aCircle := Circle new. - aCircle form: aForm. - aCircle radius: 150. - aCircle center: Sensor waitButton. - aCircle displayOn: Display - - "Circle exampleOne"! Item was removed: - ----- Method: Circle class>>exampleTwo (in category 'examples') ----- - exampleTwo - "Designate a rectangular area that should be used as the brush for - displaying the circle. Click any button at a point on the screen which - will be the center location for the circle. The curve will be displayed - with a long black form." - - | aCircle aForm | - aForm := Form fromUser. - aCircle := Circle new. - aCircle form: aForm. - aCircle radius: 150. - aCircle center: Sensor waitButton. - aCircle displayOn: Display at: 0 @ 0 rule: Form reverse - - "Circle exampleTwo"! Item was removed: - ----- Method: Circle>>computeBoundingBox (in category 'display box access') ----- - computeBoundingBox - - ^center - radius + form offset extent: form extent + (radius * 2) asPoint! Item was removed: - ----- Method: Circle>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - - 1 to: 4 do: - [:i | - super quadrant: i. - super displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: Circle>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - 1 to: 4 do: - [:i | - super quadrant: i. - super displayOn: aDisplayMedium - transformation: aTransformation - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - Path subclass: #CurveFitter - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !CurveFitter commentStamp: '' prior: 0! - I represent a conic section determined by three points p1, p2 and p3. I interpolate p1 and p3 and am tangent to line p1, p2 at p1 and line p3, p2 at p3.! Item was removed: - ----- Method: CurveFitter class>>example (in category 'examples') ----- - example - "Designate three locations on the screen by clicking any button. The - curve determined by the points will be displayed with a long black form." - - | aCurveFitter aForm | - aForm := Form extent: 1 at 30. "make a long thin Form for display " - aForm fillBlack. "turn it black" - aCurveFitter := CurveFitter new. - aCurveFitter form: aForm. "set the form for display" - "collect three Points and show them on the dispaly" - aCurveFitter firstPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aCurveFitter firstPoint. - aCurveFitter secondPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aCurveFitter secondPoint. - aCurveFitter thirdPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aCurveFitter thirdPoint. - - aCurveFitter displayOn: Display "display the CurveFitter" - - "CurveFitter example"! Item was removed: - ----- Method: CurveFitter class>>new (in category 'instance creation') ----- - new - - | newSelf | - newSelf := super new: 3. - newSelf add: 0 at 0. - newSelf add: 0 at 0. - newSelf add: 0 at 0. - ^newSelf! Item was removed: - ----- Method: CurveFitter>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - - | pa pb k s p1 p2 p3 line | - line := Line new. - line form: self form. - collectionOfPoints size < 3 ifTrue: [self error: 'Curve must have three points']. - p1 := self firstPoint. - p2 := self secondPoint. - p3 := self thirdPoint. - s := Path new. - s add: p1. - pa := p2 - p1. - pb := p3 - p2. - k := 5 max: pa x abs + pa y abs + pb x abs + pb y abs // 20. - "k is a guess as to how many line segments to use to approximate - the curve." - 1 to: k do: - [:i | - s add: pa * i // k + p1 * (k - i) + (pb * (i - 1) // k + p2 * (i - 1)) // (k - 1)]. - s add: p3. - 1 to: s size - 1 do: - [:i | - line beginPoint: (s at: i). - line endPoint: (s at: i + 1). - line displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: CurveFitter>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - | transformedPath newCurveFitter | - transformedPath := aTransformation applyTo: self. - newCurveFitter := CurveFitter new. - newCurveFitter firstPoint: transformedPath firstPoint. - newCurveFitter secondPoint: transformedPath secondPoint. - newCurveFitter thirdPoint: transformedPath thirdPoint. - newCurveFitter form: self form. - newCurveFitter - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was added: + DisplayPath subclass: #DisplayArc + instanceVariableNames: 'quadrant radius center' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayArc commentStamp: '' prior: 0! + Arcs are an unusual implementation of splines due to Ted Kaehler. Imagine two lines that meet at a corner. Now imagine two moving points; one moves from the corner to the end on one line, the other moves from the end of the other line in to the corner. Now imagine a series of lines drawn between those moving points at each step along the way (they form a sort of spider web pattern). By connecting segments of the intersecting lines, a smooth curve is achieved that is tangent to both of the original lines. Voila.! Item was added: + ----- Method: DisplayArc class>>example (in category 'examples') ----- + example + "Click the button somewhere on the screen. The designated point will + be the center of an DisplayArc with radius 50 in the 4th quadrant." + + | anDisplayArc aForm | + aForm := Form extent: 1 @ 30. "make a long thin Form for display" + aForm fillBlack. "turn it black" + anDisplayArc := DisplayArc new. + anDisplayArc form: aForm. "set the form for display" + anDisplayArc radius: 50.0. + anDisplayArc center: Sensor waitButton. + anDisplayArc quadrant: 4. + anDisplayArc displayOn: Display. + Sensor waitButton + + "DisplayArc example"! Item was added: + ----- Method: DisplayArc>>center (in category 'accessing') ----- + center + "Answer the point at the center of the receiver." + + ^center! Item was added: + ----- Method: DisplayArc>>center: (in category 'accessing') ----- + center: aPoint + "Set aPoint to be the receiver's center." + + center := aPoint! Item was added: + ----- Method: DisplayArc>>center:radius: (in category 'accessing') ----- + center: aPoint radius: anInteger + "The receiver is defined by a point at the center and a radius. The + quadrant is not reset." + + center := aPoint. + radius := anInteger! Item was added: + ----- Method: DisplayArc>>center:radius:quadrant: (in category 'accessing') ----- + center: aPoint radius: anInteger quadrant: section + "Set the receiver's quadrant to be the argument, section. The size of the + receiver is defined by the center and its radius." + + center := aPoint. + radius := anInteger. + quadrant := section! Item was added: + ----- Method: DisplayArc>>computeBoundingBox (in category 'display box access') ----- + computeBoundingBox + | aRectangle aPoint | + aRectangle := center - radius + form offset extent: form extent + (radius * 2) asPoint. + aPoint := center + form extent. + quadrant = 1 ifTrue: [^ aRectangle encompass: center x @ aPoint y]. + quadrant = 2 ifTrue: [^ aRectangle encompass: aPoint x @ aPoint y]. + quadrant = 3 ifTrue: [^ aRectangle encompass: aPoint x @ center y]. + quadrant = 4 ifTrue: [^ aRectangle encompass: center x @ center y]! Item was added: + ----- Method: DisplayArc>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + + | nSegments line angle sin cos xn yn | + nSegments := 12.0. + line := DisplayLine new. + line form: self form. + angle := (90.0 / nSegments) degreesToRadians. + sin := angle sin. + cos := angle cos. + quadrant = 1 + ifTrue: + [xn := radius asFloat. + yn := 0.0]. + quadrant = 2 + ifTrue: + [xn := 0.0. + yn := 0.0 - radius asFloat]. + quadrant = 3 + ifTrue: + [xn := 0.0 - radius asFloat. + yn := 0.0]. + quadrant = 4 + ifTrue: + [xn := 0.0. + yn := radius asFloat]. + nSegments asInteger + timesRepeat: + [ | xn1 yn1 | + xn1 := xn * cos + (yn * sin). + yn1 := yn * cos - (xn * sin). + line beginPoint: center + (xn asInteger @ yn asInteger). + line endPoint: center + (xn1 asInteger @ yn1 asInteger). + line + displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm. + xn := xn1. + yn := yn1]! Item was added: + ----- Method: DisplayArc>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + | newDisplayArc tempCenter | + newDisplayArc := DisplayArc new. + tempCenter := aTransformation applyTo: self center. + newDisplayArc center: tempCenter x asInteger @ tempCenter y asInteger. + newDisplayArc quadrant: self quadrant. + newDisplayArc radius: (self radius * aTransformation scale x) asInteger. + newDisplayArc form: self form. + newDisplayArc + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + ----- Method: DisplayArc>>quadrant (in category 'accessing') ----- + quadrant + "Answer the part of the circle represented by the receiver." + ^quadrant! Item was added: + ----- Method: DisplayArc>>quadrant: (in category 'accessing') ----- + quadrant: section + "Set the part of the circle represented by the receiver to be the argument, + section." + + quadrant := section! Item was added: + ----- Method: DisplayArc>>radius (in category 'accessing') ----- + radius + "Answer the receiver's radius." + + ^radius! Item was added: + ----- Method: DisplayArc>>radius: (in category 'accessing') ----- + radius: anInteger + "Set the receiver's radius to be the argument, anInteger." + + radius := anInteger! Item was added: + DisplayArc subclass: #DisplayCircle + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayCircle commentStamp: '' prior: 0! + I represent a full circle. I am made from four Arcs.! Item was added: + ----- Method: DisplayCircle class>>exampleOne (in category 'examples') ----- + exampleOne + "Click any button somewhere on the screen. The point will be the center + of the circcle of radius 150." + + | aDisplayCircle aForm | + aForm := Form extent: 1 at 30. + aForm fillBlack. + aDisplayCircle := DisplayCircle new. + aDisplayCircle form: aForm. + aDisplayCircle radius: 150. + aDisplayCircle center: Sensor waitButton. + aDisplayCircle displayOn: Display + + "DisplayCircle exampleOne"! Item was added: + ----- Method: DisplayCircle class>>exampleTwo (in category 'examples') ----- + exampleTwo + "Designate a rectangular area that should be used as the brush for + displaying the circle. Click any button at a point on the screen which + will be the center location for the circle. The curve will be displayed + with a long black form." + + | aDisplayCircle aForm | + aForm := Form fromUser. + aDisplayCircle := DisplayCircle new. + aDisplayCircle form: aForm. + aDisplayCircle radius: 150. + aDisplayCircle center: Sensor waitButton. + aDisplayCircle displayOn: Display at: 0 @ 0 rule: Form reverse + + "DisplayCircle exampleTwo"! Item was added: + ----- Method: DisplayCircle>>computeBoundingBox (in category 'display box access') ----- + computeBoundingBox + + ^center - radius + form offset extent: form extent + (radius * 2) asPoint! Item was added: + ----- Method: DisplayCircle>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + + 1 to: 4 do: + [:i | + super quadrant: i. + super displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayCircle>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + 1 to: 4 do: + [:i | + super quadrant: i. + super displayOn: aDisplayMedium + transformation: aTransformation + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + DisplayPath subclass: #DisplayCurveFitter + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayCurveFitter commentStamp: '' prior: 0! + I represent a conic section determined by three points p1, p2 and p3. I interpolate p1 and p3 and am tangent to line p1, p2 at p1 and line p3, p2 at p3.! Item was added: + ----- Method: DisplayCurveFitter class>>example (in category 'examples') ----- + example + "Designate three locations on the screen by clicking any button. The + curve determined by the points will be displayed with a long black form." + + | aDisplayCurveFitter aForm | + aForm := Form extent: 1 at 30. "make a long thin Form for display " + aForm fillBlack. "turn it black" + aDisplayCurveFitter := DisplayCurveFitter new. + aDisplayCurveFitter form: aForm. "set the form for display" + "collect three Points and show them on the dispaly" + aDisplayCurveFitter firstPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayCurveFitter firstPoint. + aDisplayCurveFitter secondPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayCurveFitter secondPoint. + aDisplayCurveFitter thirdPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayCurveFitter thirdPoint. + + aDisplayCurveFitter displayOn: Display "display the DisplayCurveFitter" + + "DisplayCurveFitter example"! Item was added: + ----- Method: DisplayCurveFitter class>>new (in category 'instance creation') ----- + new + + | newSelf | + newSelf := super new: 3. + newSelf add: 0 at 0. + newSelf add: 0 at 0. + newSelf add: 0 at 0. + ^newSelf! Item was added: + ----- Method: DisplayCurveFitter>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + + | pa pb k s p1 p2 p3 line | + line := DisplayLine new. + line form: self form. + collectionOfPoints size < 3 ifTrue: [self error: 'Curve must have three points']. + p1 := self firstPoint. + p2 := self secondPoint. + p3 := self thirdPoint. + s := DisplayPath new. + s add: p1. + pa := p2 - p1. + pb := p3 - p2. + k := 5 max: pa x abs + pa y abs + pb x abs + pb y abs // 20. + "k is a guess as to how many line segments to use to approximate + the curve." + 1 to: k do: + [:i | + s add: pa * i // k + p1 * (k - i) + (pb * (i - 1) // k + p2 * (i - 1)) // (k - 1)]. + s add: p3. + 1 to: s size - 1 do: + [:i | + line beginPoint: (s at: i). + line endPoint: (s at: i + 1). + line displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayCurveFitter>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + | transformedPath newDisplayCurveFitter | + transformedPath := aTransformation applyTo: self. + newDisplayCurveFitter := DisplayCurveFitter new. + newDisplayCurveFitter firstPoint: transformedPath firstPoint. + newDisplayCurveFitter secondPoint: transformedPath secondPoint. + newDisplayCurveFitter thirdPoint: transformedPath thirdPoint. + newDisplayCurveFitter form: self form. + newDisplayCurveFitter + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + DisplayPath subclass: #DisplayLine + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayLine commentStamp: '' prior: 0! + I represent the line segment specified by two points.! Item was added: + ----- Method: DisplayLine class>>example (in category 'examples') ----- + example + "Designate two places on the screen by clicking any mouse button. A + straight path with a square black form will be displayed connecting the + two selected points." + + | aDisplayLine aForm | + aForm := Form extent: 20 at 20. "make a form one quarter of inch square" + aForm fillBlack. "turn it black" + aDisplayLine := DisplayLine new. + aDisplayLine form: aForm. "use the black form for display" + aDisplayLine beginPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayLine beginPoint. + aDisplayLine endPoint: Sensor waitButton. + aDisplayLine displayOn: Display. "display the line" + + "DisplayLine example"! Item was added: + ----- Method: DisplayLine class>>from:to:withForm: (in category 'instance creation') ----- + from: beginPoint to: endPoint withForm: aForm + "Answer an instance of me with end points begingPoint and endPoint; + the source form for displaying the line is aForm." + + | newSelf | + newSelf := super new: 2. + newSelf add: beginPoint. + newSelf add: endPoint. + newSelf form: aForm. + ^newSelf! Item was added: + ----- Method: DisplayLine class>>new (in category 'instance creation') ----- + new + + | newSelf | + newSelf := super new: 2. + newSelf add: 0 at 0. + newSelf add: 0 at 0. + ^newSelf! Item was added: + ----- Method: DisplayLine>>beginPoint (in category 'accessing') ----- + beginPoint + "Answer the first end point of the receiver." + + ^self first! Item was added: + ----- Method: DisplayLine>>beginPoint: (in category 'accessing') ----- + beginPoint: aPoint + "Set the first end point of the receiver to be the argument, aPoint. + Answer aPoint." + + self at: 1 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayLine>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + "The form associated with this Path will be displayed, according + to one of the sixteen functions of two logical variables (rule), at + each point on the Line. Also the source form will be first anded + with aForm as a mask. Does not effect the state of the Path." + + collectionOfPoints size < 2 ifTrue: [self error: 'a line must have two points']. + aDisplayMedium + drawLine: self form + from: self beginPoint + aPoint + to: self endPoint + aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + ----- Method: DisplayLine>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + | newPath newDisplayLine | + newPath := aTransformation applyTo: self. + newDisplayLine := DisplayLine new. + newDisplayLine beginPoint: newPath firstPoint. + newDisplayLine endPoint: newPath secondPoint. + newDisplayLine form: self form. + newDisplayLine + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + ----- Method: DisplayLine>>displayOnPort:at: (in category 'displaying') ----- + displayOnPort: aPort at: aPoint + aPort sourceForm: self form; combinationRule: Form under; fillColor: nil. + aPort drawFrom: collectionOfPoints first + aPoint + to: collectionOfPoints last + aPoint! Item was added: + ----- Method: DisplayLine>>endPoint (in category 'accessing') ----- + endPoint + "Answer the last end point of the receiver." + + ^self last! Item was added: + ----- Method: DisplayLine>>endPoint: (in category 'accessing') ----- + endPoint: aPoint + "Set the first end point of the receiver to be the argument, aPoint. + Answer aPoint." + + self at: 2 put: aPoint. + ^aPoint! Item was added: + DisplayPath subclass: #DisplayLinearFit + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayLinearFit commentStamp: '' prior: 0! + I represent a piece-wise linear approximation to a set of points in the plane.! Item was added: + ----- Method: DisplayLinearFit class>>example (in category 'examples') ----- + example + "Select points on a Path using the red button. Terminate by selecting + any other button. Creates a Path from the points and displays it as a + piece-wise linear approximation." + + | aDisplayLinearFit aForm flag | + aDisplayLinearFit := DisplayLinearFit new. + aForm := Form extent: 1 @ 40. + aForm fillBlack. + aDisplayLinearFit form: aForm. + flag := true. + [flag] whileTrue: + [Sensor waitButton. + Sensor redButtonPressed + ifTrue: [aDisplayLinearFit add: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayLinearFit last] + ifFalse: [flag:=false]]. + aDisplayLinearFit displayOn: Display + + "DisplayLinearFit example"! Item was added: + ----- Method: DisplayLinearFit>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger + fillColor: aForm + + | line | + line := DisplayLine new. + line form: self form. + 1 to: self size - 1 do: + [:i | + line beginPoint: (self at: i). + line endPoint: (self at: i + 1). + line displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayLinearFit>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: + clipRect rule: anInteger fillColor: aForm + + | transformedPath | + "get the scaled and translated Path." + transformedPath := aTransformation applyTo: self. + transformedPath + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + DisplayObject subclass: #DisplayPath + instanceVariableNames: 'form collectionOfPoints' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayPath commentStamp: '' prior: 0! + I am the abstract superclass of the Graphic spatial primitives. I represent an ordered sequence of Points. Spatial primitives are used to generate "trajectories" such as lines and circles.! Item was added: + ----- Method: DisplayPath class>>example (in category 'examples') ----- + example + "Creates a DisplayPath from mousePoints and displays it several ways on the display screen. Messes up the display. For learning about class DisplayPath, just select the code below and execute it to create a path and see it redisplayed in another place on the screen. Each path displays using a different form. A path is indicated by pressing the red mouse button in a sequence; press any other mouse button to terminate. " + + | aDisplayPath aForm pl fl flag | + aForm := Form extent: 2 @ 40. "creates a form one inch long" + aForm fillBlack. "turns it black" + aDisplayPath := DisplayPath new. + aDisplayPath form: aForm. "use the long black form for displaying" + flag := true. + [flag] + whileTrue: + [Sensor waitButton. + Sensor redButtonPressed + ifTrue: + [aDisplayPath add: Sensor waitButton. + Sensor waitNoButton. + aForm displayOn: Display at: aDisplayPath last] + ifFalse: [flag := false]]. + Display fillWhite. + aDisplayPath displayOn: Display. "the original path" + pl := aDisplayPath translateBy: 0 @ 100. + fl := Form extent: 40 @ 40. + fl fillGray. + pl form: fl. + pl displayOn: Display. "the translated path" + Sensor waitNoButton + + "DisplayPath example"! Item was added: + ----- Method: DisplayPath class>>new (in category 'instance creation') ----- + new + + ^self basicNew initializeCollectionOfPoints! Item was added: + ----- Method: DisplayPath class>>new: (in category 'instance creation') ----- + new: anInteger + + ^self basicNew initializeCollectionOfPoints: anInteger! Item was added: + ----- Method: DisplayPath>>add: (in category 'adding') ----- + add: aPoint + "Include aPoint as one of the receiver's elements." + + ^collectionOfPoints add: aPoint! Item was added: + ----- Method: DisplayPath>>at: (in category 'accessing') ----- + at: index + "Answer the point on the receiver's path at position index." + + ^collectionOfPoints at: index! Item was added: + ----- Method: DisplayPath>>at:put: (in category 'accessing') ----- + at: index put: aPoint + "Store the argument, aPoint, as the point on the receiver's path at position + index." + + ^collectionOfPoints at: index put: aPoint! Item was added: + ----- Method: DisplayPath>>collect: (in category 'enumerating') ----- + collect: aBlock + "Evaluate aBlock with each of the receiver's elements as the argument. + Collect the resulting values into a path that is like the receiver. Answer + the new path." + + | newCollection | + newCollection := collectionOfPoints collect: aBlock. + newCollection form: self form. + ^newCollection! Item was added: + ----- Method: DisplayPath>>computeBoundingBox (in category 'display box access') ----- + computeBoundingBox + "Refer to the comment in DisplayObject|computeBoundingBox." + + | box | + box := Rectangle origin: (self at: 1) extent: 0 @ 0. + collectionOfPoints do: + [:aPoint | box swallow: (Rectangle origin: aPoint extent: 0 @ 0)]. + ^box! Item was added: + ----- Method: DisplayPath>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aDisplayPoint clippingBox: clipRectangle rule: ruleInteger fillColor: aForm + "Display this Path--offset by aPoint, clipped by clipRect and the form + associated with this Path will be displayedr according to one of the sixteen + functions of two logical variables (rule). Also the source form will be first + anded with aForm as a mask. Does not effect the state of the Path" + + collectionOfPoints do: + [:element | + self form + displayOn: aDisplayMedium + at: element + aDisplayPoint + clippingBox: clipRectangle + rule: ruleInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayPath>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: displayTransformation clippingBox: clipRectangle rule: ruleInteger fillColor: aForm + "Displays this path, translated and scaled by aTransformation. Get the + scaled and translated DisplayPath." + + | newDisplayPath transformedDisplayPath | + transformedDisplayPath := displayTransformation applyTo: self. + newDisplayPath := DisplayPath new. + transformedDisplayPath do: [:point | newDisplayPath add: point]. + newDisplayPath form: self form. + newDisplayPath + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRectangle + rule: ruleInteger + fillColor: aForm! Item was added: + ----- Method: DisplayPath>>first (in category 'accessing') ----- + first + "Answer the first point on the receiver's path; included to correspond to + OrderedCollection protocol." + + ^collectionOfPoints first! Item was added: + ----- Method: DisplayPath>>firstPoint (in category 'accessing') ----- + firstPoint + "Answer the first point on the receiver's path." + + ^collectionOfPoints first! Item was added: + ----- Method: DisplayPath>>firstPoint: (in category 'accessing') ----- + firstPoint: aPoint + "Replace the first element of the receiver with the new value aPoint. + Answer the argument aPoint." + + collectionOfPoints at: 1 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayPath>>form (in category 'accessing') ----- + form + "Answer the receiver's form, or, if form is nil, then answer a 1 x 1 black + form (a black dot)." + + | aForm | + form == nil + ifTrue: + [aForm := Form extent: 1 @ 1. + aForm fillBlack. + ^aForm] + ifFalse: + [^form]! Item was added: + ----- Method: DisplayPath>>form: (in category 'accessing') ----- + form: aForm + "Make the argument, aForm, be the receiver's form." + + form := aForm! Item was added: + ----- Method: DisplayPath>>initializeCollectionOfPoints (in category 'private') ----- + initializeCollectionOfPoints + + collectionOfPoints := OrderedCollection new! Item was added: + ----- Method: DisplayPath>>initializeCollectionOfPoints: (in category 'private') ----- + initializeCollectionOfPoints: anInteger + + collectionOfPoints := OrderedCollection new: anInteger! Item was added: + ----- Method: DisplayPath>>isEmpty (in category 'testing') ----- + isEmpty + + ^collectionOfPoints isEmpty! Item was added: + ----- Method: DisplayPath>>last (in category 'accessing') ----- + last + "Answer the last point on the receiver's path; included to correspond to + OrderedCollection protocol." + + ^collectionOfPoints last! Item was added: + ----- Method: DisplayPath>>offset (in category 'accessing') ----- + offset + "There are basically two kinds of display objects in the system: those + that, when asked to transform themselves, create a new object; and those + that side effect themselves by maintaining a record of the transformation + request (typically an offset). Path, like Rectangle and Point, is a display + object of the first kind." + + self shouldNotImplement! Item was added: + ----- Method: DisplayPath>>removeAllSuchThat: (in category 'removing') ----- + removeAllSuchThat: aBlock + "Evaluate aBlock for each element of the receiver. + Remove each element for which aBlock evaluates to true." + + collectionOfPoints removeAllSuchThat: aBlock. + ! Item was added: + ----- Method: DisplayPath>>scaleBy: (in category 'transforming') ----- + scaleBy: aPoint + "Answers a new Path scaled by aPoint. Does not affect the current data in + this Path." + + | newPath | + newPath := self species new: self size. + newPath form: self form. + collectionOfPoints do: [:element | newPath add: (element scaleBy: aPoint)]. + ^newPath! Item was added: + ----- Method: DisplayPath>>secondPoint (in category 'accessing') ----- + secondPoint + "Answer the second element of the receiver." + + ^collectionOfPoints at: 2! Item was added: + ----- Method: DisplayPath>>secondPoint: (in category 'accessing') ----- + secondPoint: aPoint + "Replace the second element of the receiver with the new value aPoint. + Answer the argument aPoint." + + collectionOfPoints at: 2 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayPath>>select: (in category 'enumerating') ----- + select: aBlock + "Evaluate aBlock with each of the receiver's elements as the argument. + Collect into a new path like the receiver only those elements for which + aBlock evaluates to true. Answer the new path." + + | newCollection | + newCollection := collectionOfPoints select: aBlock. + newCollection form: self form. + ^newCollection! Item was added: + ----- Method: DisplayPath>>size (in category 'accessing') ----- + size + "Answer the length of the receiver." + + ^collectionOfPoints size! Item was added: + ----- Method: DisplayPath>>thirdPoint (in category 'accessing') ----- + thirdPoint + "Answer the third element of the receiver." + + ^collectionOfPoints at: 3! Item was added: + ----- Method: DisplayPath>>thirdPoint: (in category 'accessing') ----- + thirdPoint: aPoint + "Replace the third element of the receiver with the new value aPoint. + Answer the argument aPoint." + + collectionOfPoints at: 3 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayPath>>translateBy: (in category 'transforming') ----- + translateBy: aPoint + "Answers a new Path whose elements are translated by aPoint. Does not + affect the elements of this Path." + + | newPath | + newPath := self species new: self size. + newPath form: self form. + collectionOfPoints do: [:element | newPath add: (element translateBy: aPoint)]. + ^newPath! Item was added: + DisplayPath subclass: #DisplaySpline + instanceVariableNames: 'coefficients' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplaySpline commentStamp: '' prior: 0! + I represent a collection of Points through which a cubic spline curve is fitted.! Item was added: + ----- Method: DisplaySpline class>>example (in category 'examples') ----- + example + "Designate points on the Path by clicking the red button. Terminate by + pressing any other button. A curve will be displayed, through the + selected points, using a long black form." + + | splineCurve aForm flag| + aForm := Form extent: 2 at 2. + aForm fillBlack. + splineCurve := DisplaySpline new. + splineCurve form: aForm. + flag := true. + [flag] whileTrue: + [Sensor waitButton. + Sensor redButtonPressed + ifTrue: + [splineCurve add: Sensor waitButton. + Sensor waitNoButton. + aForm displayOn: Display at: splineCurve last] + ifFalse: [flag:=false]]. + splineCurve computeCurve. + splineCurve isEmpty + ifFalse: [splineCurve displayOn: Display. + Sensor waitNoButton]. + + "DisplaySpline example"! Item was added: + ----- Method: DisplaySpline>>coefficients (in category 'accessing') ----- + coefficients + "Answer an eight-element Array of Arrays each of which is the length + of the receiver. The first four arrays are the values, first, second and + third derivatives, respectively, for the parametric spline in x. The last + four elements are for y." + + ^coefficients! Item was added: + ----- Method: DisplaySpline>>computeCurve (in category 'displaying') ----- + computeCurve + "Compute an array for the coefficients." + + | length extras | + length := self size. + extras := 0. + coefficients := Array new: 8. + 1 to: 8 do: [:i | coefficients at: i put: (Array new: length + extras)]. + 1 to: 5 by: 4 do: + [:k | + 1 to: length do: + [:i | (coefficients at: k) + at: i put: (k = 1 + ifTrue: [(self at: i) x asFloat] + ifFalse: [(self at: i) y asFloat])]. + 1 to: extras do: [:i | (coefficients at: k) + at: length + i put: ((coefficients at: k) + at: i + 1)]. + self derivs: (coefficients at: k) + first: (coefficients at: k + 1) + second: (coefficients at: k + 2) + third: (coefficients at: k + 3)]. + extras > 0 + ifTrue: [1 to: 8 do: + [:i | + coefficients at: i put: ((coefficients at: i) + copyFrom: 2 to: length + 1)]]! Item was added: + ----- Method: DisplaySpline>>derivs:first:second:third: (in category 'private') ----- + derivs: a first: point1 second: point2 third: point3 + "Compute the first, second and third derivitives (in coefficients) from + the Points in this Path (coefficients at: 1 and coefficients at: 5)." + + | l v anArray | + l := a size. + l < 2 ifTrue: [^self]. + l > 2 + ifTrue: + [v := Array new: l. + v at: 1 put: 4.0. + anArray := Array new: l. + anArray at: 1 put: (6.0 * ((a at: 1) - ((a at: 2) * 2.0) + (a at: 3))). + 2 to: l - 2 do: + [:i | + v at: i put: (4.0 - (1.0 / (v at: (i - 1)))). + anArray + at: i + put: (6.0 * ((a at: i) - ((a at: (i + 1)) * 2.0) + (a at: (i + 2))) + - ((anArray at: (i - 1)) / (v at: (i - 1))))]. + point2 at: (l - 1) put: ((anArray at: (l - 2)) / (v at: (l - 2))). + l - 2 to: 2 by: 0-1 do: + [:i | + point2 + at: i + put: ((anArray at: (i - 1)) - (point2 at: (i + 1)) / (v at: (i - 1)))]]. + point2 at: 1 put: (point2 at: l put: 0.0). + 1 to: l - 1 do: + [:i | point1 + at: i + put: ((a at: (i + 1)) - (a at: i) - + ((point2 at: i) * 2.0 + (point2 at: (i + 1)) / 6.0)). + point3 at: i put: ((point2 at: (i + 1)) - (point2 at: i))]! Item was added: + ----- Method: DisplaySpline>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + "Display the receiver, a spline curve, approximated by straight line + segments." + + | n line t x y x1 x2 x3 y1 y2 y3 | + collectionOfPoints size < 1 ifTrue: [self error: 'a spline must have at least one point']. + line := DisplayLine new. + line form: self form. + line beginPoint: + (x := (coefficients at: 1) at: 1) rounded @ (y := (coefficients at: 5) at: 1) rounded. + 1 to: (coefficients at: 1) size - 1 do: + [:i | + "taylor series coefficients" + x1 := (coefficients at: 2) at: i. + y1 := (coefficients at: 6) at: i. + x2 := ((coefficients at: 3) at: i) / 2.0. + y2 := ((coefficients at: 7) at: i) / 2.0. + x3 := ((coefficients at: 4) at: i) / 6.0. + y3 := ((coefficients at: 8) at: i) / 6.0. + "guess n" + n := 5 max: (x2 abs + y2 abs * 2.0 + ((coefficients at: 3) + at: i + 1) abs + ((coefficients at: 7) + at: i + 1) abs / 100.0) rounded. + 1 to: n - 1 do: + [:j | + t := j asFloat / n. + line endPoint: + (x3 * t + x2 * t + x1 * t + x) rounded + @ (y3 * t + y2 * t + y1 * t + y) rounded. + line + displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm. + line beginPoint: line endPoint]. + line beginPoint: + (x := (coefficients at: 1) at: i + 1) rounded + @ (y := (coefficients at: 5) at: i + 1) rounded. + line + displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplaySpline>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + "Get the scaled and translated path of newKnots." + + | newKnots newDisplaySpline | + newKnots := aTransformation applyTo: self. + newDisplaySpline := DisplaySpline new. + newKnots do: [:knot | newDisplaySpline add: knot]. + newDisplaySpline form: self form. + newDisplaySpline + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was changed: ----- Method: FormEditor>>curve (in category 'editing tools') ----- curve "Conic-section specified by three points designated by: first point--press red button second point--release red button third point--click red button. The resultant curve on the display is displayed according to the current form and mode." | firstPoint secondPoint thirdPoint curve drawForm | "sensor noButtonPressed ifTrue: [^self]." firstPoint := self cursorPoint. secondPoint := self rubberBandFrom: firstPoint until: [sensor noButtonPressed]. thirdPoint := self rubberBandFrom: secondPoint until: [sensor redButtonPressed]. Display depth > 1 ifTrue: [self deleteRubberBandFrom: secondPoint to: thirdPoint. self deleteRubberBandFrom: firstPoint to: secondPoint]. + curve := DisplayCurveFitter new. - curve := CurveFitter new. curve firstPoint: firstPoint. curve secondPoint: secondPoint. curve thirdPoint: thirdPoint. drawForm := form asFormOfDepth: Display depth. Display depth > 1 ifTrue: [drawForm mapColor: Color white to: Color transparent; mapColor: Color black to: color]. curve form: drawForm. curve displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: (Display depth > 1 ifTrue: [mode ~= Form erase ifTrue: [Form paint] ifFalse: [mode]] ifFalse: [mode]) fillColor: (Display depth = 1 ifTrue: [color] ifFalse: [nil]). sensor waitNoButton. hasUnsavedChanges contents: true.! Item was changed: ----- Method: FormEditor>>deleteRubberBandFrom:to: (in category 'private') ----- deleteRubberBandFrom: startPoint to: endPoint + (DisplayLine from: startPoint to: endPoint withForm: form) - (Line from: startPoint to: endPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: (Display depth = 1 ifTrue: [Color black] ifFalse: [Color gray]).! Item was changed: ----- Method: FormEditor>>line (in category 'editing tools') ----- line + "DisplayLine is specified by two points from the mouse: first point--press red - "Line is specified by two points from the mouse: first point--press red button; second point--release red button. The resultant line is displayed according to the current form and mode." | firstPoint endPoint drawForm | drawForm := form asFormOfDepth: Display depth. Display depth > 1 ifTrue: [drawForm mapColor: Color white to: Color transparent; mapColor: Color black to: color]. firstPoint := self cursorPoint. endPoint := self rubberBandFrom: firstPoint until: [sensor noButtonPressed]. endPoint isNil ifTrue: [^self]. Display depth > 1 ifTrue: [self deleteRubberBandFrom: firstPoint to: endPoint.]. + (DisplayLine from: firstPoint to: endPoint withForm: drawForm) - (Line from: firstPoint to: endPoint withForm: drawForm) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: (Display depth > 1 ifTrue: [mode ~= Form erase ifTrue: [Form paint] ifFalse: [mode]] ifFalse: [mode]) fillColor: (Display depth = 1 ifTrue: [color] ifFalse: [nil]). hasUnsavedChanges contents: true.! Item was changed: ----- Method: FormEditor>>rubberBandFrom:until: (in category 'private') ----- rubberBandFrom: startPoint until: aBlock | endPoint previousEndPoint | previousEndPoint := startPoint. [aBlock value] whileFalse: [(endPoint := self cursorPoint) = previousEndPoint ifFalse: + [(DisplayLine from: startPoint to: previousEndPoint withForm: form) - [(Line from: startPoint to: previousEndPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: Color gray. + (DisplayLine from: startPoint to: endPoint withForm: form) - (Line from: startPoint to: endPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: Color gray. previousEndPoint := endPoint]]. + (DisplayLine from: startPoint to: previousEndPoint withForm: form) - (Line from: startPoint to: previousEndPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: (Display depth = 1 ifTrue: [Color gray] ifFalse: [Color black]). ^endPoint! Item was changed: ----- Method: GraphicSymbolInstance class>>example (in category 'examples') ----- example "Simply evaluate the method and two GraphicSymbolInstances, each displaying a transformation of the same graphic symbol, will be presented on the screen. Clears the screen to white." | gate instance1 instance2 trans1 trans2 line arc f| Display fillWhite. "clear the Screen." f := Form extent: 2 @ 2. f fillBlack. gate:= GraphicSymbol new. "make a logic gate out of lines and arcs." + line:=DisplayLine new. line beginPoint: -20 @ -20. line endPoint: 0 @ -20. line form: f. - line:=Line new. line beginPoint: -20 @ -20. line endPoint: 0 @ -20. line form: f. gate add: line. + line:=DisplayLine new. line beginPoint: -20 @ 20. line endPoint: 0 @ 20. line form: f. - line:=Line new. line beginPoint: -20 @ 20. line endPoint: 0 @ 20. line form: f. gate add: line. + line:=DisplayLine new. line beginPoint: 0 @ -40. line endPoint: 0 @ 40. line form: f. - line:=Line new. line beginPoint: 0 @ -40. line endPoint: 0 @ 40. line form: f. gate add: line. + arc := DisplayArc new. arc center: 0 @ 0 radius: 40 quadrant: 1. - arc := Arc new. arc center: 0 @ 0 radius: 40 quadrant: 1. arc form: f. gate add: arc. + arc := DisplayArc new. arc center: 0 @ 0 radius: 40 quadrant: 4. - arc := Arc new. arc center: 0 @ 0 radius: 40 quadrant: 4. arc form: f. gate add: arc. "one instance at 1/2 scale." trans1:=WindowingTransformation identity. trans1:= trans1 scaleBy: 0.5 @ 0.5. trans1:= trans1 translateBy: 100 @ 100. "the other instance at 2 times scale" trans2:=WindowingTransformation identity. trans2:= trans2 scaleBy: 2.0 @ 2.0. trans2:= trans2 translateBy: 200 @ 200. instance1 := GraphicSymbolInstance new. instance1 transformation: trans1. instance1 graphicSymbol: gate. instance2 := GraphicSymbolInstance new. instance2 transformation: trans2. instance2 graphicSymbol: gate. "display both instances of the logic gate" instance1 displayOn: Display transformation: WindowingTransformation identity clippingBox: Display boundingBox rule: Form under fillColor: nil. instance2 displayOn: Display transformation: WindowingTransformation identity clippingBox: Display boundingBox rule: Form under fillColor: nil "GraphicSymbolInstance example"! Item was removed: - Path subclass: #Line - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Line commentStamp: '' prior: 0! - I represent the line segment specified by two points.! Item was removed: - ----- Method: Line class>>example (in category 'examples') ----- - example - "Designate two places on the screen by clicking any mouse button. A - straight path with a square black form will be displayed connecting the - two selected points." - - | aLine aForm | - aForm := Form extent: 20 at 20. "make a form one quarter of inch square" - aForm fillBlack. "turn it black" - aLine := Line new. - aLine form: aForm. "use the black form for display" - aLine beginPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aLine beginPoint. - aLine endPoint: Sensor waitButton. - aLine displayOn: Display. "display the line" - - "Line example"! Item was removed: - ----- Method: Line class>>from:to:withForm: (in category 'instance creation') ----- - from: beginPoint to: endPoint withForm: aForm - "Answer an instance of me with end points begingPoint and endPoint; - the source form for displaying the line is aForm." - - | newSelf | - newSelf := super new: 2. - newSelf add: beginPoint. - newSelf add: endPoint. - newSelf form: aForm. - ^newSelf! Item was removed: - ----- Method: Line class>>new (in category 'instance creation') ----- - new - - | newSelf | - newSelf := super new: 2. - newSelf add: 0 at 0. - newSelf add: 0 at 0. - ^newSelf! Item was removed: - ----- Method: Line>>beginPoint (in category 'accessing') ----- - beginPoint - "Answer the first end point of the receiver." - - ^self first! Item was removed: - ----- Method: Line>>beginPoint: (in category 'accessing') ----- - beginPoint: aPoint - "Set the first end point of the receiver to be the argument, aPoint. - Answer aPoint." - - self at: 1 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Line>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - "The form associated with this Path will be displayed, according - to one of the sixteen functions of two logical variables (rule), at - each point on the Line. Also the source form will be first anded - with aForm as a mask. Does not effect the state of the Path." - - collectionOfPoints size < 2 ifTrue: [self error: 'a line must have two points']. - aDisplayMedium - drawLine: self form - from: self beginPoint + aPoint - to: self endPoint + aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - ----- Method: Line>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - | newPath newLine | - newPath := aTransformation applyTo: self. - newLine := Line new. - newLine beginPoint: newPath firstPoint. - newLine endPoint: newPath secondPoint. - newLine form: self form. - newLine - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - ----- Method: Line>>displayOnPort:at: (in category 'displaying') ----- - displayOnPort: aPort at: aPoint - aPort sourceForm: self form; combinationRule: Form under; fillColor: nil. - aPort drawFrom: collectionOfPoints first + aPoint - to: collectionOfPoints last + aPoint! Item was removed: - ----- Method: Line>>endPoint (in category 'accessing') ----- - endPoint - "Answer the last end point of the receiver." - - ^self last! Item was removed: - ----- Method: Line>>endPoint: (in category 'accessing') ----- - endPoint: aPoint - "Set the first end point of the receiver to be the argument, aPoint. - Answer aPoint." - - self at: 2 put: aPoint. - ^aPoint! Item was removed: - Path subclass: #LinearFit - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !LinearFit commentStamp: '' prior: 0! - I represent a piece-wise linear approximation to a set of points in the plane.! Item was removed: - ----- Method: LinearFit class>>example (in category 'examples') ----- - example - "Select points on a Path using the red button. Terminate by selecting - any other button. Creates a Path from the points and displays it as a - piece-wise linear approximation." - - | aLinearFit aForm flag | - aLinearFit := LinearFit new. - aForm := Form extent: 1 @ 40. - aForm fillBlack. - aLinearFit form: aForm. - flag := true. - [flag] whileTrue: - [Sensor waitButton. - Sensor redButtonPressed - ifTrue: [aLinearFit add: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aLinearFit last] - ifFalse: [flag:=false]]. - aLinearFit displayOn: Display - - "LinearFit example"! Item was removed: - ----- Method: LinearFit>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger - fillColor: aForm - - | line | - line := Line new. - line form: self form. - 1 to: self size - 1 do: - [:i | - line beginPoint: (self at: i). - line endPoint: (self at: i + 1). - line displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: LinearFit>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: - clipRect rule: anInteger fillColor: aForm - - | transformedPath | - "get the scaled and translated Path." - transformedPath := aTransformation applyTo: self. - transformedPath - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - DisplayObject subclass: #Path - instanceVariableNames: 'form collectionOfPoints' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Path commentStamp: '' prior: 0! - I am the abstract superclass of the Graphic spatial primitives. I represent an ordered sequence of Points. Spatial primitives are used to generate "trajectories" such as lines and circles.! Item was removed: - ----- Method: Path class>>example (in category 'examples') ----- - example - "Creates a Path from mousePoints and displays it several ways on the display screen. Messes up the display. For learning about class Path, just select the code below and execute it to create a path and see it redisplayed in another place on the screen. Each path displays using a different form. A path is indicated by pressing the red mouse button in a sequence; press any other mouse button to terminate. " - - | aPath aForm pl fl flag | - aForm := Form extent: 2 @ 40. "creates a form one inch long" - aForm fillBlack. "turns it black" - aPath := Path new. - aPath form: aForm. "use the long black form for displaying" - flag := true. - [flag] - whileTrue: - [Sensor waitButton. - Sensor redButtonPressed - ifTrue: - [aPath add: Sensor waitButton. - Sensor waitNoButton. - aForm displayOn: Display at: aPath last] - ifFalse: [flag := false]]. - Display fillWhite. - aPath displayOn: Display. "the original path" - pl := aPath translateBy: 0 @ 100. - fl := Form extent: 40 @ 40. - fl fillGray. - pl form: fl. - pl displayOn: Display. "the translated path" - Sensor waitNoButton - - "Path example"! Item was removed: - ----- Method: Path class>>new (in category 'instance creation') ----- - new - - ^self basicNew initializeCollectionOfPoints! Item was removed: - ----- Method: Path class>>new: (in category 'instance creation') ----- - new: anInteger - - ^self basicNew initializeCollectionOfPoints: anInteger! Item was removed: - ----- Method: Path>>add: (in category 'adding') ----- - add: aPoint - "Include aPoint as one of the receiver's elements." - - ^collectionOfPoints add: aPoint! Item was removed: - ----- Method: Path>>at: (in category 'accessing') ----- - at: index - "Answer the point on the receiver's path at position index." - - ^collectionOfPoints at: index! Item was removed: - ----- Method: Path>>at:put: (in category 'accessing') ----- - at: index put: aPoint - "Store the argument, aPoint, as the point on the receiver's path at position - index." - - ^collectionOfPoints at: index put: aPoint! Item was removed: - ----- Method: Path>>collect: (in category 'enumerating') ----- - collect: aBlock - "Evaluate aBlock with each of the receiver's elements as the argument. - Collect the resulting values into a path that is like the receiver. Answer - the new path." - - | newCollection | - newCollection := collectionOfPoints collect: aBlock. - newCollection form: self form. - ^newCollection! Item was removed: - ----- Method: Path>>computeBoundingBox (in category 'display box access') ----- - computeBoundingBox - "Refer to the comment in DisplayObject|computeBoundingBox." - - | box | - box := Rectangle origin: (self at: 1) extent: 0 @ 0. - collectionOfPoints do: - [:aPoint | box swallow: (Rectangle origin: aPoint extent: 0 @ 0)]. - ^box! Item was removed: - ----- Method: Path>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aDisplayPoint clippingBox: clipRectangle rule: ruleInteger fillColor: aForm - "Display this Path--offset by aPoint, clipped by clipRect and the form - associated with this Path will be displayedr according to one of the sixteen - functions of two logical variables (rule). Also the source form will be first - anded with aForm as a mask. Does not effect the state of the Path" - - collectionOfPoints do: - [:element | - self form - displayOn: aDisplayMedium - at: element + aDisplayPoint - clippingBox: clipRectangle - rule: ruleInteger - fillColor: aForm]! Item was removed: - ----- Method: Path>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: displayTransformation clippingBox: clipRectangle rule: ruleInteger fillColor: aForm - "Displays this path, translated and scaled by aTransformation. Get the - scaled and translated Path." - - | newPath transformedPath | - transformedPath := displayTransformation applyTo: self. - newPath := Path new. - transformedPath do: [:point | newPath add: point]. - newPath form: self form. - newPath - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRectangle - rule: ruleInteger - fillColor: aForm! Item was removed: - ----- Method: Path>>first (in category 'accessing') ----- - first - "Answer the first point on the receiver's path; included to correspond to - OrderedCollection protocol." - - ^collectionOfPoints first! Item was removed: - ----- Method: Path>>firstPoint (in category 'accessing') ----- - firstPoint - "Answer the first point on the receiver's path." - - ^collectionOfPoints first! Item was removed: - ----- Method: Path>>firstPoint: (in category 'accessing') ----- - firstPoint: aPoint - "Replace the first element of the receiver with the new value aPoint. - Answer the argument aPoint." - - collectionOfPoints at: 1 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Path>>form (in category 'accessing') ----- - form - "Answer the receiver's form, or, if form is nil, then answer a 1 x 1 black - form (a black dot)." - - | aForm | - form == nil - ifTrue: - [aForm := Form extent: 1 @ 1. - aForm fillBlack. - ^aForm] - ifFalse: - [^form]! Item was removed: - ----- Method: Path>>form: (in category 'accessing') ----- - form: aForm - "Make the argument, aForm, be the receiver's form." - - form := aForm! Item was removed: - ----- Method: Path>>initializeCollectionOfPoints (in category 'private') ----- - initializeCollectionOfPoints - - collectionOfPoints := OrderedCollection new! Item was removed: - ----- Method: Path>>initializeCollectionOfPoints: (in category 'private') ----- - initializeCollectionOfPoints: anInteger - - collectionOfPoints := OrderedCollection new: anInteger! Item was removed: - ----- Method: Path>>isEmpty (in category 'testing') ----- - isEmpty - - ^collectionOfPoints isEmpty! Item was removed: - ----- Method: Path>>last (in category 'accessing') ----- - last - "Answer the last point on the receiver's path; included to correspond to - OrderedCollection protocol." - - ^collectionOfPoints last! Item was removed: - ----- Method: Path>>offset (in category 'accessing') ----- - offset - "There are basically two kinds of display objects in the system: those - that, when asked to transform themselves, create a new object; and those - that side effect themselves by maintaining a record of the transformation - request (typically an offset). Path, like Rectangle and Point, is a display - object of the first kind." - - self shouldNotImplement! Item was removed: - ----- Method: Path>>removeAllSuchThat: (in category 'removing') ----- - removeAllSuchThat: aBlock - "Evaluate aBlock for each element of the receiver. - Remove each element for which aBlock evaluates to true." - - collectionOfPoints removeAllSuchThat: aBlock. - ! Item was removed: - ----- Method: Path>>scaleBy: (in category 'transforming') ----- - scaleBy: aPoint - "Answers a new Path scaled by aPoint. Does not affect the current data in - this Path." - - | newPath | - newPath := self species new: self size. - newPath form: self form. - collectionOfPoints do: [:element | newPath add: (element scaleBy: aPoint)]. - ^newPath! Item was removed: - ----- Method: Path>>secondPoint (in category 'accessing') ----- - secondPoint - "Answer the second element of the receiver." - - ^collectionOfPoints at: 2! Item was removed: - ----- Method: Path>>secondPoint: (in category 'accessing') ----- - secondPoint: aPoint - "Replace the second element of the receiver with the new value aPoint. - Answer the argument aPoint." - - collectionOfPoints at: 2 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Path>>select: (in category 'enumerating') ----- - select: aBlock - "Evaluate aBlock with each of the receiver's elements as the argument. - Collect into a new path like the receiver only those elements for which - aBlock evaluates to true. Answer the new path." - - | newCollection | - newCollection := collectionOfPoints select: aBlock. - newCollection form: self form. - ^newCollection! Item was removed: - ----- Method: Path>>size (in category 'accessing') ----- - size - "Answer the length of the receiver." - - ^collectionOfPoints size! Item was removed: - ----- Method: Path>>thirdPoint (in category 'accessing') ----- - thirdPoint - "Answer the third element of the receiver." - - ^collectionOfPoints at: 3! Item was removed: - ----- Method: Path>>thirdPoint: (in category 'accessing') ----- - thirdPoint: aPoint - "Replace the third element of the receiver with the new value aPoint. - Answer the argument aPoint." - - collectionOfPoints at: 3 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Path>>translateBy: (in category 'transforming') ----- - translateBy: aPoint - "Answers a new Path whose elements are translated by aPoint. Does not - affect the elements of this Path." - - | newPath | - newPath := self species new: self size. - newPath form: self form. - collectionOfPoints do: [:element | newPath add: (element translateBy: aPoint)]. - ^newPath! Item was removed: - Path subclass: #Spline - instanceVariableNames: 'coefficients' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Spline commentStamp: '' prior: 0! - I represent a collection of Points through which a cubic spline curve is fitted.! Item was removed: - ----- Method: Spline class>>example (in category 'examples') ----- - example - "Designate points on the Path by clicking the red button. Terminate by - pressing any other button. A curve will be displayed, through the - selected points, using a long black form." - - | splineCurve aForm flag| - aForm := Form extent: 2 at 2. - aForm fillBlack. - splineCurve := Spline new. - splineCurve form: aForm. - flag := true. - [flag] whileTrue: - [Sensor waitButton. - Sensor redButtonPressed - ifTrue: - [splineCurve add: Sensor waitButton. - Sensor waitNoButton. - aForm displayOn: Display at: splineCurve last] - ifFalse: [flag:=false]]. - splineCurve computeCurve. - splineCurve isEmpty - ifFalse: [splineCurve displayOn: Display. - Sensor waitNoButton]. - - "Spline example"! Item was removed: - ----- Method: Spline>>coefficients (in category 'accessing') ----- - coefficients - "Answer an eight-element Array of Arrays each of which is the length - of the receiver. The first four arrays are the values, first, second and - third derivatives, respectively, for the parametric spline in x. The last - four elements are for y." - - ^coefficients! Item was removed: - ----- Method: Spline>>computeCurve (in category 'displaying') ----- - computeCurve - "Compute an array for the coefficients." - - | length extras | - length := self size. - extras := 0. - coefficients := Array new: 8. - 1 to: 8 do: [:i | coefficients at: i put: (Array new: length + extras)]. - 1 to: 5 by: 4 do: - [:k | - 1 to: length do: - [:i | (coefficients at: k) - at: i put: (k = 1 - ifTrue: [(self at: i) x asFloat] - ifFalse: [(self at: i) y asFloat])]. - 1 to: extras do: [:i | (coefficients at: k) - at: length + i put: ((coefficients at: k) - at: i + 1)]. - self derivs: (coefficients at: k) - first: (coefficients at: k + 1) - second: (coefficients at: k + 2) - third: (coefficients at: k + 3)]. - extras > 0 - ifTrue: [1 to: 8 do: - [:i | - coefficients at: i put: ((coefficients at: i) - copyFrom: 2 to: length + 1)]]! Item was removed: - ----- Method: Spline>>derivs:first:second:third: (in category 'private') ----- - derivs: a first: point1 second: point2 third: point3 - "Compute the first, second and third derivitives (in coefficients) from - the Points in this Path (coefficients at: 1 and coefficients at: 5)." - - | l v anArray | - l := a size. - l < 2 ifTrue: [^self]. - l > 2 - ifTrue: - [v := Array new: l. - v at: 1 put: 4.0. - anArray := Array new: l. - anArray at: 1 put: (6.0 * ((a at: 1) - ((a at: 2) * 2.0) + (a at: 3))). - 2 to: l - 2 do: - [:i | - v at: i put: (4.0 - (1.0 / (v at: (i - 1)))). - anArray - at: i - put: (6.0 * ((a at: i) - ((a at: (i + 1)) * 2.0) + (a at: (i + 2))) - - ((anArray at: (i - 1)) / (v at: (i - 1))))]. - point2 at: (l - 1) put: ((anArray at: (l - 2)) / (v at: (l - 2))). - l - 2 to: 2 by: 0-1 do: - [:i | - point2 - at: i - put: ((anArray at: (i - 1)) - (point2 at: (i + 1)) / (v at: (i - 1)))]]. - point2 at: 1 put: (point2 at: l put: 0.0). - 1 to: l - 1 do: - [:i | point1 - at: i - put: ((a at: (i + 1)) - (a at: i) - - ((point2 at: i) * 2.0 + (point2 at: (i + 1)) / 6.0)). - point3 at: i put: ((point2 at: (i + 1)) - (point2 at: i))]! Item was removed: - ----- Method: Spline>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - "Display the receiver, a spline curve, approximated by straight line - segments." - - | n line t x y x1 x2 x3 y1 y2 y3 | - collectionOfPoints size < 1 ifTrue: [self error: 'a spline must have at least one point']. - line := Line new. - line form: self form. - line beginPoint: - (x := (coefficients at: 1) at: 1) rounded @ (y := (coefficients at: 5) at: 1) rounded. - 1 to: (coefficients at: 1) size - 1 do: - [:i | - "taylor series coefficients" - x1 := (coefficients at: 2) at: i. - y1 := (coefficients at: 6) at: i. - x2 := ((coefficients at: 3) at: i) / 2.0. - y2 := ((coefficients at: 7) at: i) / 2.0. - x3 := ((coefficients at: 4) at: i) / 6.0. - y3 := ((coefficients at: 8) at: i) / 6.0. - "guess n" - n := 5 max: (x2 abs + y2 abs * 2.0 + ((coefficients at: 3) - at: i + 1) abs + ((coefficients at: 7) - at: i + 1) abs / 100.0) rounded. - 1 to: n - 1 do: - [:j | - t := j asFloat / n. - line endPoint: - (x3 * t + x2 * t + x1 * t + x) rounded - @ (y3 * t + y2 * t + y1 * t + y) rounded. - line - displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm. - line beginPoint: line endPoint]. - line beginPoint: - (x := (coefficients at: 1) at: i + 1) rounded - @ (y := (coefficients at: 5) at: i + 1) rounded. - line - displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: Spline>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - "Get the scaled and translated path of newKnots." - - | newKnots newSpline | - newKnots := aTransformation applyTo: self. - newSpline := Spline new. - newKnots do: [:knot | newSpline add: knot]. - newSpline form: self form. - newSpline - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! From marcel.taeumel at hpi.de Tue Mar 9 12:39:17 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 13:39:17 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> <,> Message-ID: Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result |    aButton withAllOwners       do: [:morph | result nextPut: morph color]       upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners >    collect: [:morph | morph color] >    until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100)         collect: [:x | x squared]         where: [:x | x even]         until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock         | result supplier |         supplier := self readStream.         result := {} writeStream.         [[supplier atEnd]             whileFalse: [ | val |               val := supplier next.               (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)].               (untilBlock value: val) ifTrue: [^result contents]]         ] value.         ^result contents collect: colBlock until: untilBlock         ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock         ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html [http://forum.world.st/Squeak-Dev-f45488.html] -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 12:40:29 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 13:40:29 +0100 Subject: [squeak-dev] The Inbox: ST80-mt.265.mcz In-Reply-To: References: Message-ID: Hi all! I would like to merge this into Trunk in a day or two if nobody objects. :-) See the discussion here: http://forum.world.st/Proposal-Geometry-Classes-td5093998.html [http://forum.world.st/Proposal-Geometry-Classes-td5093998.html] Best, Marcel Am 09.03.2021 13:33:52 schrieb commits at source.squeak.org : A new version of ST80 was added to project The Inbox: http://source.squeak.org/inbox/ST80-mt.265.mcz ==================== Summary ==================== Name: ST80-mt.265 Author: mt Time: 9 March 2021, 1:33:39.525921 pm UUID: 1b02e796-d790-b34d-9f4f-dd406f43e130 Ancestors: ST80-mt.264 Free the names Path, Arc, Circle, Line, Spline to be used in a prospective Math package. =============== Diff against ST80-mt.264 =============== Item was removed: - Path subclass: #Arc - instanceVariableNames: 'quadrant radius center' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Arc commentStamp: '' prior: 0! - Arcs are an unusual implementation of splines due to Ted Kaehler. Imagine two lines that meet at a corner. Now imagine two moving points; one moves from the corner to the end on one line, the other moves from the end of the other line in to the corner. Now imagine a series of lines drawn between those moving points at each step along the way (they form a sort of spider web pattern). By connecting segments of the intersecting lines, a smooth curve is achieved that is tangent to both of the original lines. Voila.! Item was removed: - ----- Method: Arc class>>example (in category 'examples') ----- - example - "Click the button somewhere on the screen. The designated point will - be the center of an Arc with radius 50 in the 4th quadrant." - - | anArc aForm | - aForm := Form extent: 1 @ 30. "make a long thin Form for display" - aForm fillBlack. "turn it black" - anArc := Arc new. - anArc form: aForm. "set the form for display" - anArc radius: 50.0. - anArc center: Sensor waitButton. - anArc quadrant: 4. - anArc displayOn: Display. - Sensor waitButton - - "Arc example"! Item was removed: - ----- Method: Arc>>center (in category 'accessing') ----- - center - "Answer the point at the center of the receiver." - - ^center! Item was removed: - ----- Method: Arc>>center: (in category 'accessing') ----- - center: aPoint - "Set aPoint to be the receiver's center." - - center := aPoint! Item was removed: - ----- Method: Arc>>center:radius: (in category 'accessing') ----- - center: aPoint radius: anInteger - "The receiver is defined by a point at the center and a radius. The - quadrant is not reset." - - center := aPoint. - radius := anInteger! Item was removed: - ----- Method: Arc>>center:radius:quadrant: (in category 'accessing') ----- - center: aPoint radius: anInteger quadrant: section - "Set the receiver's quadrant to be the argument, section. The size of the - receiver is defined by the center and its radius." - - center := aPoint. - radius := anInteger. - quadrant := section! Item was removed: - ----- Method: Arc>>computeBoundingBox (in category 'display box access') ----- - computeBoundingBox - | aRectangle aPoint | - aRectangle := center - radius + form offset extent: form extent + (radius * 2) asPoint. - aPoint := center + form extent. - quadrant = 1 ifTrue: [^ aRectangle encompass: center x @ aPoint y]. - quadrant = 2 ifTrue: [^ aRectangle encompass: aPoint x @ aPoint y]. - quadrant = 3 ifTrue: [^ aRectangle encompass: aPoint x @ center y]. - quadrant = 4 ifTrue: [^ aRectangle encompass: center x @ center y]! Item was removed: - ----- Method: Arc>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - - | nSegments line angle sin cos xn yn | - nSegments := 12.0. - line := Line new. - line form: self form. - angle := (90.0 / nSegments) degreesToRadians. - sin := angle sin. - cos := angle cos. - quadrant = 1 - ifTrue: - [xn := radius asFloat. - yn := 0.0]. - quadrant = 2 - ifTrue: - [xn := 0.0. - yn := 0.0 - radius asFloat]. - quadrant = 3 - ifTrue: - [xn := 0.0 - radius asFloat. - yn := 0.0]. - quadrant = 4 - ifTrue: - [xn := 0.0. - yn := radius asFloat]. - nSegments asInteger - timesRepeat: - [ | xn1 yn1 | - xn1 := xn * cos + (yn * sin). - yn1 := yn * cos - (xn * sin). - line beginPoint: center + (xn asInteger @ yn asInteger). - line endPoint: center + (xn1 asInteger @ yn1 asInteger). - line - displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm. - xn := xn1. - yn := yn1]! Item was removed: - ----- Method: Arc>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - | newArc tempCenter | - newArc := Arc new. - tempCenter := aTransformation applyTo: self center. - newArc center: tempCenter x asInteger @ tempCenter y asInteger. - newArc quadrant: self quadrant. - newArc radius: (self radius * aTransformation scale x) asInteger. - newArc form: self form. - newArc - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - ----- Method: Arc>>quadrant (in category 'accessing') ----- - quadrant - "Answer the part of the circle represented by the receiver." - ^quadrant! Item was removed: - ----- Method: Arc>>quadrant: (in category 'accessing') ----- - quadrant: section - "Set the part of the circle represented by the receiver to be the argument, - section." - - quadrant := section! Item was removed: - ----- Method: Arc>>radius (in category 'accessing') ----- - radius - "Answer the receiver's radius." - - ^radius! Item was removed: - ----- Method: Arc>>radius: (in category 'accessing') ----- - radius: anInteger - "Set the receiver's radius to be the argument, anInteger." - - radius := anInteger! Item was removed: - Arc subclass: #Circle - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Circle commentStamp: '' prior: 0! - I represent a full circle. I am made from four Arcs.! Item was removed: - ----- Method: Circle class>>exampleOne (in category 'examples') ----- - exampleOne - "Click any button somewhere on the screen. The point will be the center - of the circcle of radius 150." - - | aCircle aForm | - aForm := Form extent: 1 at 30. - aForm fillBlack. - aCircle := Circle new. - aCircle form: aForm. - aCircle radius: 150. - aCircle center: Sensor waitButton. - aCircle displayOn: Display - - "Circle exampleOne"! Item was removed: - ----- Method: Circle class>>exampleTwo (in category 'examples') ----- - exampleTwo - "Designate a rectangular area that should be used as the brush for - displaying the circle. Click any button at a point on the screen which - will be the center location for the circle. The curve will be displayed - with a long black form." - - | aCircle aForm | - aForm := Form fromUser. - aCircle := Circle new. - aCircle form: aForm. - aCircle radius: 150. - aCircle center: Sensor waitButton. - aCircle displayOn: Display at: 0 @ 0 rule: Form reverse - - "Circle exampleTwo"! Item was removed: - ----- Method: Circle>>computeBoundingBox (in category 'display box access') ----- - computeBoundingBox - - ^center - radius + form offset extent: form extent + (radius * 2) asPoint! Item was removed: - ----- Method: Circle>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - - 1 to: 4 do: - [:i | - super quadrant: i. - super displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: Circle>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - 1 to: 4 do: - [:i | - super quadrant: i. - super displayOn: aDisplayMedium - transformation: aTransformation - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - Path subclass: #CurveFitter - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !CurveFitter commentStamp: '' prior: 0! - I represent a conic section determined by three points p1, p2 and p3. I interpolate p1 and p3 and am tangent to line p1, p2 at p1 and line p3, p2 at p3.! Item was removed: - ----- Method: CurveFitter class>>example (in category 'examples') ----- - example - "Designate three locations on the screen by clicking any button. The - curve determined by the points will be displayed with a long black form." - - | aCurveFitter aForm | - aForm := Form extent: 1 at 30. "make a long thin Form for display " - aForm fillBlack. "turn it black" - aCurveFitter := CurveFitter new. - aCurveFitter form: aForm. "set the form for display" - "collect three Points and show them on the dispaly" - aCurveFitter firstPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aCurveFitter firstPoint. - aCurveFitter secondPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aCurveFitter secondPoint. - aCurveFitter thirdPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aCurveFitter thirdPoint. - - aCurveFitter displayOn: Display "display the CurveFitter" - - "CurveFitter example"! Item was removed: - ----- Method: CurveFitter class>>new (in category 'instance creation') ----- - new - - | newSelf | - newSelf := super new: 3. - newSelf add: 0 at 0. - newSelf add: 0 at 0. - newSelf add: 0 at 0. - ^newSelf! Item was removed: - ----- Method: CurveFitter>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - - | pa pb k s p1 p2 p3 line | - line := Line new. - line form: self form. - collectionOfPoints size < 3 ifTrue: [self error: 'Curve must have three points']. - p1 := self firstPoint. - p2 := self secondPoint. - p3 := self thirdPoint. - s := Path new. - s add: p1. - pa := p2 - p1. - pb := p3 - p2. - k := 5 max: pa x abs + pa y abs + pb x abs + pb y abs // 20. - "k is a guess as to how many line segments to use to approximate - the curve." - 1 to: k do: - [:i | - s add: pa * i // k + p1 * (k - i) + (pb * (i - 1) // k + p2 * (i - 1)) // (k - 1)]. - s add: p3. - 1 to: s size - 1 do: - [:i | - line beginPoint: (s at: i). - line endPoint: (s at: i + 1). - line displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: CurveFitter>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - | transformedPath newCurveFitter | - transformedPath := aTransformation applyTo: self. - newCurveFitter := CurveFitter new. - newCurveFitter firstPoint: transformedPath firstPoint. - newCurveFitter secondPoint: transformedPath secondPoint. - newCurveFitter thirdPoint: transformedPath thirdPoint. - newCurveFitter form: self form. - newCurveFitter - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was added: + DisplayPath subclass: #DisplayArc + instanceVariableNames: 'quadrant radius center' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayArc commentStamp: '' prior: 0! + Arcs are an unusual implementation of splines due to Ted Kaehler. Imagine two lines that meet at a corner. Now imagine two moving points; one moves from the corner to the end on one line, the other moves from the end of the other line in to the corner. Now imagine a series of lines drawn between those moving points at each step along the way (they form a sort of spider web pattern). By connecting segments of the intersecting lines, a smooth curve is achieved that is tangent to both of the original lines. Voila.! Item was added: + ----- Method: DisplayArc class>>example (in category 'examples') ----- + example + "Click the button somewhere on the screen. The designated point will + be the center of an DisplayArc with radius 50 in the 4th quadrant." + + | anDisplayArc aForm | + aForm := Form extent: 1 @ 30. "make a long thin Form for display" + aForm fillBlack. "turn it black" + anDisplayArc := DisplayArc new. + anDisplayArc form: aForm. "set the form for display" + anDisplayArc radius: 50.0. + anDisplayArc center: Sensor waitButton. + anDisplayArc quadrant: 4. + anDisplayArc displayOn: Display. + Sensor waitButton + + "DisplayArc example"! Item was added: + ----- Method: DisplayArc>>center (in category 'accessing') ----- + center + "Answer the point at the center of the receiver." + + ^center! Item was added: + ----- Method: DisplayArc>>center: (in category 'accessing') ----- + center: aPoint + "Set aPoint to be the receiver's center." + + center := aPoint! Item was added: + ----- Method: DisplayArc>>center:radius: (in category 'accessing') ----- + center: aPoint radius: anInteger + "The receiver is defined by a point at the center and a radius. The + quadrant is not reset." + + center := aPoint. + radius := anInteger! Item was added: + ----- Method: DisplayArc>>center:radius:quadrant: (in category 'accessing') ----- + center: aPoint radius: anInteger quadrant: section + "Set the receiver's quadrant to be the argument, section. The size of the + receiver is defined by the center and its radius." + + center := aPoint. + radius := anInteger. + quadrant := section! Item was added: + ----- Method: DisplayArc>>computeBoundingBox (in category 'display box access') ----- + computeBoundingBox + | aRectangle aPoint | + aRectangle := center - radius + form offset extent: form extent + (radius * 2) asPoint. + aPoint := center + form extent. + quadrant = 1 ifTrue: [^ aRectangle encompass: center x @ aPoint y]. + quadrant = 2 ifTrue: [^ aRectangle encompass: aPoint x @ aPoint y]. + quadrant = 3 ifTrue: [^ aRectangle encompass: aPoint x @ center y]. + quadrant = 4 ifTrue: [^ aRectangle encompass: center x @ center y]! Item was added: + ----- Method: DisplayArc>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + + | nSegments line angle sin cos xn yn | + nSegments := 12.0. + line := DisplayLine new. + line form: self form. + angle := (90.0 / nSegments) degreesToRadians. + sin := angle sin. + cos := angle cos. + quadrant = 1 + ifTrue: + [xn := radius asFloat. + yn := 0.0]. + quadrant = 2 + ifTrue: + [xn := 0.0. + yn := 0.0 - radius asFloat]. + quadrant = 3 + ifTrue: + [xn := 0.0 - radius asFloat. + yn := 0.0]. + quadrant = 4 + ifTrue: + [xn := 0.0. + yn := radius asFloat]. + nSegments asInteger + timesRepeat: + [ | xn1 yn1 | + xn1 := xn * cos + (yn * sin). + yn1 := yn * cos - (xn * sin). + line beginPoint: center + (xn asInteger @ yn asInteger). + line endPoint: center + (xn1 asInteger @ yn1 asInteger). + line + displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm. + xn := xn1. + yn := yn1]! Item was added: + ----- Method: DisplayArc>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + | newDisplayArc tempCenter | + newDisplayArc := DisplayArc new. + tempCenter := aTransformation applyTo: self center. + newDisplayArc center: tempCenter x asInteger @ tempCenter y asInteger. + newDisplayArc quadrant: self quadrant. + newDisplayArc radius: (self radius * aTransformation scale x) asInteger. + newDisplayArc form: self form. + newDisplayArc + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + ----- Method: DisplayArc>>quadrant (in category 'accessing') ----- + quadrant + "Answer the part of the circle represented by the receiver." + ^quadrant! Item was added: + ----- Method: DisplayArc>>quadrant: (in category 'accessing') ----- + quadrant: section + "Set the part of the circle represented by the receiver to be the argument, + section." + + quadrant := section! Item was added: + ----- Method: DisplayArc>>radius (in category 'accessing') ----- + radius + "Answer the receiver's radius." + + ^radius! Item was added: + ----- Method: DisplayArc>>radius: (in category 'accessing') ----- + radius: anInteger + "Set the receiver's radius to be the argument, anInteger." + + radius := anInteger! Item was added: + DisplayArc subclass: #DisplayCircle + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayCircle commentStamp: '' prior: 0! + I represent a full circle. I am made from four Arcs.! Item was added: + ----- Method: DisplayCircle class>>exampleOne (in category 'examples') ----- + exampleOne + "Click any button somewhere on the screen. The point will be the center + of the circcle of radius 150." + + | aDisplayCircle aForm | + aForm := Form extent: 1 at 30. + aForm fillBlack. + aDisplayCircle := DisplayCircle new. + aDisplayCircle form: aForm. + aDisplayCircle radius: 150. + aDisplayCircle center: Sensor waitButton. + aDisplayCircle displayOn: Display + + "DisplayCircle exampleOne"! Item was added: + ----- Method: DisplayCircle class>>exampleTwo (in category 'examples') ----- + exampleTwo + "Designate a rectangular area that should be used as the brush for + displaying the circle. Click any button at a point on the screen which + will be the center location for the circle. The curve will be displayed + with a long black form." + + | aDisplayCircle aForm | + aForm := Form fromUser. + aDisplayCircle := DisplayCircle new. + aDisplayCircle form: aForm. + aDisplayCircle radius: 150. + aDisplayCircle center: Sensor waitButton. + aDisplayCircle displayOn: Display at: 0 @ 0 rule: Form reverse + + "DisplayCircle exampleTwo"! Item was added: + ----- Method: DisplayCircle>>computeBoundingBox (in category 'display box access') ----- + computeBoundingBox + + ^center - radius + form offset extent: form extent + (radius * 2) asPoint! Item was added: + ----- Method: DisplayCircle>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + + 1 to: 4 do: + [:i | + super quadrant: i. + super displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayCircle>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + 1 to: 4 do: + [:i | + super quadrant: i. + super displayOn: aDisplayMedium + transformation: aTransformation + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + DisplayPath subclass: #DisplayCurveFitter + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayCurveFitter commentStamp: '' prior: 0! + I represent a conic section determined by three points p1, p2 and p3. I interpolate p1 and p3 and am tangent to line p1, p2 at p1 and line p3, p2 at p3.! Item was added: + ----- Method: DisplayCurveFitter class>>example (in category 'examples') ----- + example + "Designate three locations on the screen by clicking any button. The + curve determined by the points will be displayed with a long black form." + + | aDisplayCurveFitter aForm | + aForm := Form extent: 1 at 30. "make a long thin Form for display " + aForm fillBlack. "turn it black" + aDisplayCurveFitter := DisplayCurveFitter new. + aDisplayCurveFitter form: aForm. "set the form for display" + "collect three Points and show them on the dispaly" + aDisplayCurveFitter firstPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayCurveFitter firstPoint. + aDisplayCurveFitter secondPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayCurveFitter secondPoint. + aDisplayCurveFitter thirdPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayCurveFitter thirdPoint. + + aDisplayCurveFitter displayOn: Display "display the DisplayCurveFitter" + + "DisplayCurveFitter example"! Item was added: + ----- Method: DisplayCurveFitter class>>new (in category 'instance creation') ----- + new + + | newSelf | + newSelf := super new: 3. + newSelf add: 0 at 0. + newSelf add: 0 at 0. + newSelf add: 0 at 0. + ^newSelf! Item was added: + ----- Method: DisplayCurveFitter>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + + | pa pb k s p1 p2 p3 line | + line := DisplayLine new. + line form: self form. + collectionOfPoints size < 3 ifTrue: [self error: 'Curve must have three points']. + p1 := self firstPoint. + p2 := self secondPoint. + p3 := self thirdPoint. + s := DisplayPath new. + s add: p1. + pa := p2 - p1. + pb := p3 - p2. + k := 5 max: pa x abs + pa y abs + pb x abs + pb y abs // 20. + "k is a guess as to how many line segments to use to approximate + the curve." + 1 to: k do: + [:i | + s add: pa * i // k + p1 * (k - i) + (pb * (i - 1) // k + p2 * (i - 1)) // (k - 1)]. + s add: p3. + 1 to: s size - 1 do: + [:i | + line beginPoint: (s at: i). + line endPoint: (s at: i + 1). + line displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayCurveFitter>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + | transformedPath newDisplayCurveFitter | + transformedPath := aTransformation applyTo: self. + newDisplayCurveFitter := DisplayCurveFitter new. + newDisplayCurveFitter firstPoint: transformedPath firstPoint. + newDisplayCurveFitter secondPoint: transformedPath secondPoint. + newDisplayCurveFitter thirdPoint: transformedPath thirdPoint. + newDisplayCurveFitter form: self form. + newDisplayCurveFitter + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + DisplayPath subclass: #DisplayLine + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayLine commentStamp: '' prior: 0! + I represent the line segment specified by two points.! Item was added: + ----- Method: DisplayLine class>>example (in category 'examples') ----- + example + "Designate two places on the screen by clicking any mouse button. A + straight path with a square black form will be displayed connecting the + two selected points." + + | aDisplayLine aForm | + aForm := Form extent: 20 at 20. "make a form one quarter of inch square" + aForm fillBlack. "turn it black" + aDisplayLine := DisplayLine new. + aDisplayLine form: aForm. "use the black form for display" + aDisplayLine beginPoint: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayLine beginPoint. + aDisplayLine endPoint: Sensor waitButton. + aDisplayLine displayOn: Display. "display the line" + + "DisplayLine example"! Item was added: + ----- Method: DisplayLine class>>from:to:withForm: (in category 'instance creation') ----- + from: beginPoint to: endPoint withForm: aForm + "Answer an instance of me with end points begingPoint and endPoint; + the source form for displaying the line is aForm." + + | newSelf | + newSelf := super new: 2. + newSelf add: beginPoint. + newSelf add: endPoint. + newSelf form: aForm. + ^newSelf! Item was added: + ----- Method: DisplayLine class>>new (in category 'instance creation') ----- + new + + | newSelf | + newSelf := super new: 2. + newSelf add: 0 at 0. + newSelf add: 0 at 0. + ^newSelf! Item was added: + ----- Method: DisplayLine>>beginPoint (in category 'accessing') ----- + beginPoint + "Answer the first end point of the receiver." + + ^self first! Item was added: + ----- Method: DisplayLine>>beginPoint: (in category 'accessing') ----- + beginPoint: aPoint + "Set the first end point of the receiver to be the argument, aPoint. + Answer aPoint." + + self at: 1 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayLine>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + "The form associated with this Path will be displayed, according + to one of the sixteen functions of two logical variables (rule), at + each point on the Line. Also the source form will be first anded + with aForm as a mask. Does not effect the state of the Path." + + collectionOfPoints size < 2 ifTrue: [self error: 'a line must have two points']. + aDisplayMedium + drawLine: self form + from: self beginPoint + aPoint + to: self endPoint + aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + ----- Method: DisplayLine>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + + | newPath newDisplayLine | + newPath := aTransformation applyTo: self. + newDisplayLine := DisplayLine new. + newDisplayLine beginPoint: newPath firstPoint. + newDisplayLine endPoint: newPath secondPoint. + newDisplayLine form: self form. + newDisplayLine + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + ----- Method: DisplayLine>>displayOnPort:at: (in category 'displaying') ----- + displayOnPort: aPort at: aPoint + aPort sourceForm: self form; combinationRule: Form under; fillColor: nil. + aPort drawFrom: collectionOfPoints first + aPoint + to: collectionOfPoints last + aPoint! Item was added: + ----- Method: DisplayLine>>endPoint (in category 'accessing') ----- + endPoint + "Answer the last end point of the receiver." + + ^self last! Item was added: + ----- Method: DisplayLine>>endPoint: (in category 'accessing') ----- + endPoint: aPoint + "Set the first end point of the receiver to be the argument, aPoint. + Answer aPoint." + + self at: 2 put: aPoint. + ^aPoint! Item was added: + DisplayPath subclass: #DisplayLinearFit + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayLinearFit commentStamp: '' prior: 0! + I represent a piece-wise linear approximation to a set of points in the plane.! Item was added: + ----- Method: DisplayLinearFit class>>example (in category 'examples') ----- + example + "Select points on a Path using the red button. Terminate by selecting + any other button. Creates a Path from the points and displays it as a + piece-wise linear approximation." + + | aDisplayLinearFit aForm flag | + aDisplayLinearFit := DisplayLinearFit new. + aForm := Form extent: 1 @ 40. + aForm fillBlack. + aDisplayLinearFit form: aForm. + flag := true. + [flag] whileTrue: + [Sensor waitButton. + Sensor redButtonPressed + ifTrue: [aDisplayLinearFit add: Sensor waitButton. Sensor waitNoButton. + aForm displayOn: Display at: aDisplayLinearFit last] + ifFalse: [flag:=false]]. + aDisplayLinearFit displayOn: Display + + "DisplayLinearFit example"! Item was added: + ----- Method: DisplayLinearFit>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger + fillColor: aForm + + | line | + line := DisplayLine new. + line form: self form. + 1 to: self size - 1 do: + [:i | + line beginPoint: (self at: i). + line endPoint: (self at: i + 1). + line displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayLinearFit>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: + clipRect rule: anInteger fillColor: aForm + + | transformedPath | + "get the scaled and translated Path." + transformedPath := aTransformation applyTo: self. + transformedPath + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was added: + DisplayObject subclass: #DisplayPath + instanceVariableNames: 'form collectionOfPoints' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplayPath commentStamp: '' prior: 0! + I am the abstract superclass of the Graphic spatial primitives. I represent an ordered sequence of Points. Spatial primitives are used to generate "trajectories" such as lines and circles.! Item was added: + ----- Method: DisplayPath class>>example (in category 'examples') ----- + example + "Creates a DisplayPath from mousePoints and displays it several ways on the display screen. Messes up the display. For learning about class DisplayPath, just select the code below and execute it to create a path and see it redisplayed in another place on the screen. Each path displays using a different form. A path is indicated by pressing the red mouse button in a sequence; press any other mouse button to terminate. " + + | aDisplayPath aForm pl fl flag | + aForm := Form extent: 2 @ 40. "creates a form one inch long" + aForm fillBlack. "turns it black" + aDisplayPath := DisplayPath new. + aDisplayPath form: aForm. "use the long black form for displaying" + flag := true. + [flag] + whileTrue: + [Sensor waitButton. + Sensor redButtonPressed + ifTrue: + [aDisplayPath add: Sensor waitButton. + Sensor waitNoButton. + aForm displayOn: Display at: aDisplayPath last] + ifFalse: [flag := false]]. + Display fillWhite. + aDisplayPath displayOn: Display. "the original path" + pl := aDisplayPath translateBy: 0 @ 100. + fl := Form extent: 40 @ 40. + fl fillGray. + pl form: fl. + pl displayOn: Display. "the translated path" + Sensor waitNoButton + + "DisplayPath example"! Item was added: + ----- Method: DisplayPath class>>new (in category 'instance creation') ----- + new + + ^self basicNew initializeCollectionOfPoints! Item was added: + ----- Method: DisplayPath class>>new: (in category 'instance creation') ----- + new: anInteger + + ^self basicNew initializeCollectionOfPoints: anInteger! Item was added: + ----- Method: DisplayPath>>add: (in category 'adding') ----- + add: aPoint + "Include aPoint as one of the receiver's elements." + + ^collectionOfPoints add: aPoint! Item was added: + ----- Method: DisplayPath>>at: (in category 'accessing') ----- + at: index + "Answer the point on the receiver's path at position index." + + ^collectionOfPoints at: index! Item was added: + ----- Method: DisplayPath>>at:put: (in category 'accessing') ----- + at: index put: aPoint + "Store the argument, aPoint, as the point on the receiver's path at position + index." + + ^collectionOfPoints at: index put: aPoint! Item was added: + ----- Method: DisplayPath>>collect: (in category 'enumerating') ----- + collect: aBlock + "Evaluate aBlock with each of the receiver's elements as the argument. + Collect the resulting values into a path that is like the receiver. Answer + the new path." + + | newCollection | + newCollection := collectionOfPoints collect: aBlock. + newCollection form: self form. + ^newCollection! Item was added: + ----- Method: DisplayPath>>computeBoundingBox (in category 'display box access') ----- + computeBoundingBox + "Refer to the comment in DisplayObject|computeBoundingBox." + + | box | + box := Rectangle origin: (self at: 1) extent: 0 @ 0. + collectionOfPoints do: + [:aPoint | box swallow: (Rectangle origin: aPoint extent: 0 @ 0)]. + ^box! Item was added: + ----- Method: DisplayPath>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aDisplayPoint clippingBox: clipRectangle rule: ruleInteger fillColor: aForm + "Display this Path--offset by aPoint, clipped by clipRect and the form + associated with this Path will be displayedr according to one of the sixteen + functions of two logical variables (rule). Also the source form will be first + anded with aForm as a mask. Does not effect the state of the Path" + + collectionOfPoints do: + [:element | + self form + displayOn: aDisplayMedium + at: element + aDisplayPoint + clippingBox: clipRectangle + rule: ruleInteger + fillColor: aForm]! Item was added: + ----- Method: DisplayPath>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: displayTransformation clippingBox: clipRectangle rule: ruleInteger fillColor: aForm + "Displays this path, translated and scaled by aTransformation. Get the + scaled and translated DisplayPath." + + | newDisplayPath transformedDisplayPath | + transformedDisplayPath := displayTransformation applyTo: self. + newDisplayPath := DisplayPath new. + transformedDisplayPath do: [:point | newDisplayPath add: point]. + newDisplayPath form: self form. + newDisplayPath + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRectangle + rule: ruleInteger + fillColor: aForm! Item was added: + ----- Method: DisplayPath>>first (in category 'accessing') ----- + first + "Answer the first point on the receiver's path; included to correspond to + OrderedCollection protocol." + + ^collectionOfPoints first! Item was added: + ----- Method: DisplayPath>>firstPoint (in category 'accessing') ----- + firstPoint + "Answer the first point on the receiver's path." + + ^collectionOfPoints first! Item was added: + ----- Method: DisplayPath>>firstPoint: (in category 'accessing') ----- + firstPoint: aPoint + "Replace the first element of the receiver with the new value aPoint. + Answer the argument aPoint." + + collectionOfPoints at: 1 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayPath>>form (in category 'accessing') ----- + form + "Answer the receiver's form, or, if form is nil, then answer a 1 x 1 black + form (a black dot)." + + | aForm | + form == nil + ifTrue: + [aForm := Form extent: 1 @ 1. + aForm fillBlack. + ^aForm] + ifFalse: + [^form]! Item was added: + ----- Method: DisplayPath>>form: (in category 'accessing') ----- + form: aForm + "Make the argument, aForm, be the receiver's form." + + form := aForm! Item was added: + ----- Method: DisplayPath>>initializeCollectionOfPoints (in category 'private') ----- + initializeCollectionOfPoints + + collectionOfPoints := OrderedCollection new! Item was added: + ----- Method: DisplayPath>>initializeCollectionOfPoints: (in category 'private') ----- + initializeCollectionOfPoints: anInteger + + collectionOfPoints := OrderedCollection new: anInteger! Item was added: + ----- Method: DisplayPath>>isEmpty (in category 'testing') ----- + isEmpty + + ^collectionOfPoints isEmpty! Item was added: + ----- Method: DisplayPath>>last (in category 'accessing') ----- + last + "Answer the last point on the receiver's path; included to correspond to + OrderedCollection protocol." + + ^collectionOfPoints last! Item was added: + ----- Method: DisplayPath>>offset (in category 'accessing') ----- + offset + "There are basically two kinds of display objects in the system: those + that, when asked to transform themselves, create a new object; and those + that side effect themselves by maintaining a record of the transformation + request (typically an offset). Path, like Rectangle and Point, is a display + object of the first kind." + + self shouldNotImplement! Item was added: + ----- Method: DisplayPath>>removeAllSuchThat: (in category 'removing') ----- + removeAllSuchThat: aBlock + "Evaluate aBlock for each element of the receiver. + Remove each element for which aBlock evaluates to true." + + collectionOfPoints removeAllSuchThat: aBlock. + ! Item was added: + ----- Method: DisplayPath>>scaleBy: (in category 'transforming') ----- + scaleBy: aPoint + "Answers a new Path scaled by aPoint. Does not affect the current data in + this Path." + + | newPath | + newPath := self species new: self size. + newPath form: self form. + collectionOfPoints do: [:element | newPath add: (element scaleBy: aPoint)]. + ^newPath! Item was added: + ----- Method: DisplayPath>>secondPoint (in category 'accessing') ----- + secondPoint + "Answer the second element of the receiver." + + ^collectionOfPoints at: 2! Item was added: + ----- Method: DisplayPath>>secondPoint: (in category 'accessing') ----- + secondPoint: aPoint + "Replace the second element of the receiver with the new value aPoint. + Answer the argument aPoint." + + collectionOfPoints at: 2 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayPath>>select: (in category 'enumerating') ----- + select: aBlock + "Evaluate aBlock with each of the receiver's elements as the argument. + Collect into a new path like the receiver only those elements for which + aBlock evaluates to true. Answer the new path." + + | newCollection | + newCollection := collectionOfPoints select: aBlock. + newCollection form: self form. + ^newCollection! Item was added: + ----- Method: DisplayPath>>size (in category 'accessing') ----- + size + "Answer the length of the receiver." + + ^collectionOfPoints size! Item was added: + ----- Method: DisplayPath>>thirdPoint (in category 'accessing') ----- + thirdPoint + "Answer the third element of the receiver." + + ^collectionOfPoints at: 3! Item was added: + ----- Method: DisplayPath>>thirdPoint: (in category 'accessing') ----- + thirdPoint: aPoint + "Replace the third element of the receiver with the new value aPoint. + Answer the argument aPoint." + + collectionOfPoints at: 3 put: aPoint. + ^aPoint! Item was added: + ----- Method: DisplayPath>>translateBy: (in category 'transforming') ----- + translateBy: aPoint + "Answers a new Path whose elements are translated by aPoint. Does not + affect the elements of this Path." + + | newPath | + newPath := self species new: self size. + newPath form: self form. + collectionOfPoints do: [:element | newPath add: (element translateBy: aPoint)]. + ^newPath! Item was added: + DisplayPath subclass: #DisplaySpline + instanceVariableNames: 'coefficients' + classVariableNames: '' + poolDictionaries: '' + category: 'ST80-Paths'! + + !DisplaySpline commentStamp: '' prior: 0! + I represent a collection of Points through which a cubic spline curve is fitted.! Item was added: + ----- Method: DisplaySpline class>>example (in category 'examples') ----- + example + "Designate points on the Path by clicking the red button. Terminate by + pressing any other button. A curve will be displayed, through the + selected points, using a long black form." + + | splineCurve aForm flag| + aForm := Form extent: 2 at 2. + aForm fillBlack. + splineCurve := DisplaySpline new. + splineCurve form: aForm. + flag := true. + [flag] whileTrue: + [Sensor waitButton. + Sensor redButtonPressed + ifTrue: + [splineCurve add: Sensor waitButton. + Sensor waitNoButton. + aForm displayOn: Display at: splineCurve last] + ifFalse: [flag:=false]]. + splineCurve computeCurve. + splineCurve isEmpty + ifFalse: [splineCurve displayOn: Display. + Sensor waitNoButton]. + + "DisplaySpline example"! Item was added: + ----- Method: DisplaySpline>>coefficients (in category 'accessing') ----- + coefficients + "Answer an eight-element Array of Arrays each of which is the length + of the receiver. The first four arrays are the values, first, second and + third derivatives, respectively, for the parametric spline in x. The last + four elements are for y." + + ^coefficients! Item was added: + ----- Method: DisplaySpline>>computeCurve (in category 'displaying') ----- + computeCurve + "Compute an array for the coefficients." + + | length extras | + length := self size. + extras := 0. + coefficients := Array new: 8. + 1 to: 8 do: [:i | coefficients at: i put: (Array new: length + extras)]. + 1 to: 5 by: 4 do: + [:k | + 1 to: length do: + [:i | (coefficients at: k) + at: i put: (k = 1 + ifTrue: [(self at: i) x asFloat] + ifFalse: [(self at: i) y asFloat])]. + 1 to: extras do: [:i | (coefficients at: k) + at: length + i put: ((coefficients at: k) + at: i + 1)]. + self derivs: (coefficients at: k) + first: (coefficients at: k + 1) + second: (coefficients at: k + 2) + third: (coefficients at: k + 3)]. + extras > 0 + ifTrue: [1 to: 8 do: + [:i | + coefficients at: i put: ((coefficients at: i) + copyFrom: 2 to: length + 1)]]! Item was added: + ----- Method: DisplaySpline>>derivs:first:second:third: (in category 'private') ----- + derivs: a first: point1 second: point2 third: point3 + "Compute the first, second and third derivitives (in coefficients) from + the Points in this Path (coefficients at: 1 and coefficients at: 5)." + + | l v anArray | + l := a size. + l < 2 ifTrue: [^self]. + l > 2 + ifTrue: + [v := Array new: l. + v at: 1 put: 4.0. + anArray := Array new: l. + anArray at: 1 put: (6.0 * ((a at: 1) - ((a at: 2) * 2.0) + (a at: 3))). + 2 to: l - 2 do: + [:i | + v at: i put: (4.0 - (1.0 / (v at: (i - 1)))). + anArray + at: i + put: (6.0 * ((a at: i) - ((a at: (i + 1)) * 2.0) + (a at: (i + 2))) + - ((anArray at: (i - 1)) / (v at: (i - 1))))]. + point2 at: (l - 1) put: ((anArray at: (l - 2)) / (v at: (l - 2))). + l - 2 to: 2 by: 0-1 do: + [:i | + point2 + at: i + put: ((anArray at: (i - 1)) - (point2 at: (i + 1)) / (v at: (i - 1)))]]. + point2 at: 1 put: (point2 at: l put: 0.0). + 1 to: l - 1 do: + [:i | point1 + at: i + put: ((a at: (i + 1)) - (a at: i) - + ((point2 at: i) * 2.0 + (point2 at: (i + 1)) / 6.0)). + point3 at: i put: ((point2 at: (i + 1)) - (point2 at: i))]! Item was added: + ----- Method: DisplaySpline>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm + "Display the receiver, a spline curve, approximated by straight line + segments." + + | n line t x y x1 x2 x3 y1 y2 y3 | + collectionOfPoints size < 1 ifTrue: [self error: 'a spline must have at least one point']. + line := DisplayLine new. + line form: self form. + line beginPoint: + (x := (coefficients at: 1) at: 1) rounded @ (y := (coefficients at: 5) at: 1) rounded. + 1 to: (coefficients at: 1) size - 1 do: + [:i | + "taylor series coefficients" + x1 := (coefficients at: 2) at: i. + y1 := (coefficients at: 6) at: i. + x2 := ((coefficients at: 3) at: i) / 2.0. + y2 := ((coefficients at: 7) at: i) / 2.0. + x3 := ((coefficients at: 4) at: i) / 6.0. + y3 := ((coefficients at: 8) at: i) / 6.0. + "guess n" + n := 5 max: (x2 abs + y2 abs * 2.0 + ((coefficients at: 3) + at: i + 1) abs + ((coefficients at: 7) + at: i + 1) abs / 100.0) rounded. + 1 to: n - 1 do: + [:j | + t := j asFloat / n. + line endPoint: + (x3 * t + x2 * t + x1 * t + x) rounded + @ (y3 * t + y2 * t + y1 * t + y) rounded. + line + displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm. + line beginPoint: line endPoint]. + line beginPoint: + (x := (coefficients at: 1) at: i + 1) rounded + @ (y := (coefficients at: 5) at: i + 1) rounded. + line + displayOn: aDisplayMedium + at: aPoint + clippingBox: clipRect + rule: anInteger + fillColor: aForm]! Item was added: + ----- Method: DisplaySpline>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- + displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm + "Get the scaled and translated path of newKnots." + + | newKnots newDisplaySpline | + newKnots := aTransformation applyTo: self. + newDisplaySpline := DisplaySpline new. + newKnots do: [:knot | newDisplaySpline add: knot]. + newDisplaySpline form: self form. + newDisplaySpline + displayOn: aDisplayMedium + at: 0 @ 0 + clippingBox: clipRect + rule: anInteger + fillColor: aForm! Item was changed: ----- Method: FormEditor>>curve (in category 'editing tools') ----- curve "Conic-section specified by three points designated by: first point--press red button second point--release red button third point--click red button. The resultant curve on the display is displayed according to the current form and mode." | firstPoint secondPoint thirdPoint curve drawForm | "sensor noButtonPressed ifTrue: [^self]." firstPoint := self cursorPoint. secondPoint := self rubberBandFrom: firstPoint until: [sensor noButtonPressed]. thirdPoint := self rubberBandFrom: secondPoint until: [sensor redButtonPressed]. Display depth > 1 ifTrue: [self deleteRubberBandFrom: secondPoint to: thirdPoint. self deleteRubberBandFrom: firstPoint to: secondPoint]. + curve := DisplayCurveFitter new. - curve := CurveFitter new. curve firstPoint: firstPoint. curve secondPoint: secondPoint. curve thirdPoint: thirdPoint. drawForm := form asFormOfDepth: Display depth. Display depth > 1 ifTrue: [drawForm mapColor: Color white to: Color transparent; mapColor: Color black to: color]. curve form: drawForm. curve displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: (Display depth > 1 ifTrue: [mode ~= Form erase ifTrue: [Form paint] ifFalse: [mode]] ifFalse: [mode]) fillColor: (Display depth = 1 ifTrue: [color] ifFalse: [nil]). sensor waitNoButton. hasUnsavedChanges contents: true.! Item was changed: ----- Method: FormEditor>>deleteRubberBandFrom:to: (in category 'private') ----- deleteRubberBandFrom: startPoint to: endPoint + (DisplayLine from: startPoint to: endPoint withForm: form) - (Line from: startPoint to: endPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: (Display depth = 1 ifTrue: [Color black] ifFalse: [Color gray]).! Item was changed: ----- Method: FormEditor>>line (in category 'editing tools') ----- line + "DisplayLine is specified by two points from the mouse: first point--press red - "Line is specified by two points from the mouse: first point--press red button; second point--release red button. The resultant line is displayed according to the current form and mode." | firstPoint endPoint drawForm | drawForm := form asFormOfDepth: Display depth. Display depth > 1 ifTrue: [drawForm mapColor: Color white to: Color transparent; mapColor: Color black to: color]. firstPoint := self cursorPoint. endPoint := self rubberBandFrom: firstPoint until: [sensor noButtonPressed]. endPoint isNil ifTrue: [^self]. Display depth > 1 ifTrue: [self deleteRubberBandFrom: firstPoint to: endPoint.]. + (DisplayLine from: firstPoint to: endPoint withForm: drawForm) - (Line from: firstPoint to: endPoint withForm: drawForm) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: (Display depth > 1 ifTrue: [mode ~= Form erase ifTrue: [Form paint] ifFalse: [mode]] ifFalse: [mode]) fillColor: (Display depth = 1 ifTrue: [color] ifFalse: [nil]). hasUnsavedChanges contents: true.! Item was changed: ----- Method: FormEditor>>rubberBandFrom:until: (in category 'private') ----- rubberBandFrom: startPoint until: aBlock | endPoint previousEndPoint | previousEndPoint := startPoint. [aBlock value] whileFalse: [(endPoint := self cursorPoint) = previousEndPoint ifFalse: + [(DisplayLine from: startPoint to: previousEndPoint withForm: form) - [(Line from: startPoint to: previousEndPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: Color gray. + (DisplayLine from: startPoint to: endPoint withForm: form) - (Line from: startPoint to: endPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: Color gray. previousEndPoint := endPoint]]. + (DisplayLine from: startPoint to: previousEndPoint withForm: form) - (Line from: startPoint to: previousEndPoint withForm: form) displayOn: Display at: 0 @ 0 clippingBox: view insetDisplayBox rule: Form reverse fillColor: (Display depth = 1 ifTrue: [Color gray] ifFalse: [Color black]). ^endPoint! Item was changed: ----- Method: GraphicSymbolInstance class>>example (in category 'examples') ----- example "Simply evaluate the method and two GraphicSymbolInstances, each displaying a transformation of the same graphic symbol, will be presented on the screen. Clears the screen to white." | gate instance1 instance2 trans1 trans2 line arc f| Display fillWhite. "clear the Screen." f := Form extent: 2 @ 2. f fillBlack. gate:= GraphicSymbol new. "make a logic gate out of lines and arcs." + line:=DisplayLine new. line beginPoint: -20 @ -20. line endPoint: 0 @ -20. line form: f. - line:=Line new. line beginPoint: -20 @ -20. line endPoint: 0 @ -20. line form: f. gate add: line. + line:=DisplayLine new. line beginPoint: -20 @ 20. line endPoint: 0 @ 20. line form: f. - line:=Line new. line beginPoint: -20 @ 20. line endPoint: 0 @ 20. line form: f. gate add: line. + line:=DisplayLine new. line beginPoint: 0 @ -40. line endPoint: 0 @ 40. line form: f. - line:=Line new. line beginPoint: 0 @ -40. line endPoint: 0 @ 40. line form: f. gate add: line. + arc := DisplayArc new. arc center: 0 @ 0 radius: 40 quadrant: 1. - arc := Arc new. arc center: 0 @ 0 radius: 40 quadrant: 1. arc form: f. gate add: arc. + arc := DisplayArc new. arc center: 0 @ 0 radius: 40 quadrant: 4. - arc := Arc new. arc center: 0 @ 0 radius: 40 quadrant: 4. arc form: f. gate add: arc. "one instance at 1/2 scale." trans1:=WindowingTransformation identity. trans1:= trans1 scaleBy: 0.5 @ 0.5. trans1:= trans1 translateBy: 100 @ 100. "the other instance at 2 times scale" trans2:=WindowingTransformation identity. trans2:= trans2 scaleBy: 2.0 @ 2.0. trans2:= trans2 translateBy: 200 @ 200. instance1 := GraphicSymbolInstance new. instance1 transformation: trans1. instance1 graphicSymbol: gate. instance2 := GraphicSymbolInstance new. instance2 transformation: trans2. instance2 graphicSymbol: gate. "display both instances of the logic gate" instance1 displayOn: Display transformation: WindowingTransformation identity clippingBox: Display boundingBox rule: Form under fillColor: nil. instance2 displayOn: Display transformation: WindowingTransformation identity clippingBox: Display boundingBox rule: Form under fillColor: nil "GraphicSymbolInstance example"! Item was removed: - Path subclass: #Line - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Line commentStamp: '' prior: 0! - I represent the line segment specified by two points.! Item was removed: - ----- Method: Line class>>example (in category 'examples') ----- - example - "Designate two places on the screen by clicking any mouse button. A - straight path with a square black form will be displayed connecting the - two selected points." - - | aLine aForm | - aForm := Form extent: 20 at 20. "make a form one quarter of inch square" - aForm fillBlack. "turn it black" - aLine := Line new. - aLine form: aForm. "use the black form for display" - aLine beginPoint: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aLine beginPoint. - aLine endPoint: Sensor waitButton. - aLine displayOn: Display. "display the line" - - "Line example"! Item was removed: - ----- Method: Line class>>from:to:withForm: (in category 'instance creation') ----- - from: beginPoint to: endPoint withForm: aForm - "Answer an instance of me with end points begingPoint and endPoint; - the source form for displaying the line is aForm." - - | newSelf | - newSelf := super new: 2. - newSelf add: beginPoint. - newSelf add: endPoint. - newSelf form: aForm. - ^newSelf! Item was removed: - ----- Method: Line class>>new (in category 'instance creation') ----- - new - - | newSelf | - newSelf := super new: 2. - newSelf add: 0 at 0. - newSelf add: 0 at 0. - ^newSelf! Item was removed: - ----- Method: Line>>beginPoint (in category 'accessing') ----- - beginPoint - "Answer the first end point of the receiver." - - ^self first! Item was removed: - ----- Method: Line>>beginPoint: (in category 'accessing') ----- - beginPoint: aPoint - "Set the first end point of the receiver to be the argument, aPoint. - Answer aPoint." - - self at: 1 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Line>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - "The form associated with this Path will be displayed, according - to one of the sixteen functions of two logical variables (rule), at - each point on the Line. Also the source form will be first anded - with aForm as a mask. Does not effect the state of the Path." - - collectionOfPoints size < 2 ifTrue: [self error: 'a line must have two points']. - aDisplayMedium - drawLine: self form - from: self beginPoint + aPoint - to: self endPoint + aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - ----- Method: Line>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - - | newPath newLine | - newPath := aTransformation applyTo: self. - newLine := Line new. - newLine beginPoint: newPath firstPoint. - newLine endPoint: newPath secondPoint. - newLine form: self form. - newLine - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - ----- Method: Line>>displayOnPort:at: (in category 'displaying') ----- - displayOnPort: aPort at: aPoint - aPort sourceForm: self form; combinationRule: Form under; fillColor: nil. - aPort drawFrom: collectionOfPoints first + aPoint - to: collectionOfPoints last + aPoint! Item was removed: - ----- Method: Line>>endPoint (in category 'accessing') ----- - endPoint - "Answer the last end point of the receiver." - - ^self last! Item was removed: - ----- Method: Line>>endPoint: (in category 'accessing') ----- - endPoint: aPoint - "Set the first end point of the receiver to be the argument, aPoint. - Answer aPoint." - - self at: 2 put: aPoint. - ^aPoint! Item was removed: - Path subclass: #LinearFit - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !LinearFit commentStamp: '' prior: 0! - I represent a piece-wise linear approximation to a set of points in the plane.! Item was removed: - ----- Method: LinearFit class>>example (in category 'examples') ----- - example - "Select points on a Path using the red button. Terminate by selecting - any other button. Creates a Path from the points and displays it as a - piece-wise linear approximation." - - | aLinearFit aForm flag | - aLinearFit := LinearFit new. - aForm := Form extent: 1 @ 40. - aForm fillBlack. - aLinearFit form: aForm. - flag := true. - [flag] whileTrue: - [Sensor waitButton. - Sensor redButtonPressed - ifTrue: [aLinearFit add: Sensor waitButton. Sensor waitNoButton. - aForm displayOn: Display at: aLinearFit last] - ifFalse: [flag:=false]]. - aLinearFit displayOn: Display - - "LinearFit example"! Item was removed: - ----- Method: LinearFit>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger - fillColor: aForm - - | line | - line := Line new. - line form: self form. - 1 to: self size - 1 do: - [:i | - line beginPoint: (self at: i). - line endPoint: (self at: i + 1). - line displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: LinearFit>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: - clipRect rule: anInteger fillColor: aForm - - | transformedPath | - "get the scaled and translated Path." - transformedPath := aTransformation applyTo: self. - transformedPath - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! Item was removed: - DisplayObject subclass: #Path - instanceVariableNames: 'form collectionOfPoints' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Path commentStamp: '' prior: 0! - I am the abstract superclass of the Graphic spatial primitives. I represent an ordered sequence of Points. Spatial primitives are used to generate "trajectories" such as lines and circles.! Item was removed: - ----- Method: Path class>>example (in category 'examples') ----- - example - "Creates a Path from mousePoints and displays it several ways on the display screen. Messes up the display. For learning about class Path, just select the code below and execute it to create a path and see it redisplayed in another place on the screen. Each path displays using a different form. A path is indicated by pressing the red mouse button in a sequence; press any other mouse button to terminate. " - - | aPath aForm pl fl flag | - aForm := Form extent: 2 @ 40. "creates a form one inch long" - aForm fillBlack. "turns it black" - aPath := Path new. - aPath form: aForm. "use the long black form for displaying" - flag := true. - [flag] - whileTrue: - [Sensor waitButton. - Sensor redButtonPressed - ifTrue: - [aPath add: Sensor waitButton. - Sensor waitNoButton. - aForm displayOn: Display at: aPath last] - ifFalse: [flag := false]]. - Display fillWhite. - aPath displayOn: Display. "the original path" - pl := aPath translateBy: 0 @ 100. - fl := Form extent: 40 @ 40. - fl fillGray. - pl form: fl. - pl displayOn: Display. "the translated path" - Sensor waitNoButton - - "Path example"! Item was removed: - ----- Method: Path class>>new (in category 'instance creation') ----- - new - - ^self basicNew initializeCollectionOfPoints! Item was removed: - ----- Method: Path class>>new: (in category 'instance creation') ----- - new: anInteger - - ^self basicNew initializeCollectionOfPoints: anInteger! Item was removed: - ----- Method: Path>>add: (in category 'adding') ----- - add: aPoint - "Include aPoint as one of the receiver's elements." - - ^collectionOfPoints add: aPoint! Item was removed: - ----- Method: Path>>at: (in category 'accessing') ----- - at: index - "Answer the point on the receiver's path at position index." - - ^collectionOfPoints at: index! Item was removed: - ----- Method: Path>>at:put: (in category 'accessing') ----- - at: index put: aPoint - "Store the argument, aPoint, as the point on the receiver's path at position - index." - - ^collectionOfPoints at: index put: aPoint! Item was removed: - ----- Method: Path>>collect: (in category 'enumerating') ----- - collect: aBlock - "Evaluate aBlock with each of the receiver's elements as the argument. - Collect the resulting values into a path that is like the receiver. Answer - the new path." - - | newCollection | - newCollection := collectionOfPoints collect: aBlock. - newCollection form: self form. - ^newCollection! Item was removed: - ----- Method: Path>>computeBoundingBox (in category 'display box access') ----- - computeBoundingBox - "Refer to the comment in DisplayObject|computeBoundingBox." - - | box | - box := Rectangle origin: (self at: 1) extent: 0 @ 0. - collectionOfPoints do: - [:aPoint | box swallow: (Rectangle origin: aPoint extent: 0 @ 0)]. - ^box! Item was removed: - ----- Method: Path>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aDisplayPoint clippingBox: clipRectangle rule: ruleInteger fillColor: aForm - "Display this Path--offset by aPoint, clipped by clipRect and the form - associated with this Path will be displayedr according to one of the sixteen - functions of two logical variables (rule). Also the source form will be first - anded with aForm as a mask. Does not effect the state of the Path" - - collectionOfPoints do: - [:element | - self form - displayOn: aDisplayMedium - at: element + aDisplayPoint - clippingBox: clipRectangle - rule: ruleInteger - fillColor: aForm]! Item was removed: - ----- Method: Path>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: displayTransformation clippingBox: clipRectangle rule: ruleInteger fillColor: aForm - "Displays this path, translated and scaled by aTransformation. Get the - scaled and translated Path." - - | newPath transformedPath | - transformedPath := displayTransformation applyTo: self. - newPath := Path new. - transformedPath do: [:point | newPath add: point]. - newPath form: self form. - newPath - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRectangle - rule: ruleInteger - fillColor: aForm! Item was removed: - ----- Method: Path>>first (in category 'accessing') ----- - first - "Answer the first point on the receiver's path; included to correspond to - OrderedCollection protocol." - - ^collectionOfPoints first! Item was removed: - ----- Method: Path>>firstPoint (in category 'accessing') ----- - firstPoint - "Answer the first point on the receiver's path." - - ^collectionOfPoints first! Item was removed: - ----- Method: Path>>firstPoint: (in category 'accessing') ----- - firstPoint: aPoint - "Replace the first element of the receiver with the new value aPoint. - Answer the argument aPoint." - - collectionOfPoints at: 1 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Path>>form (in category 'accessing') ----- - form - "Answer the receiver's form, or, if form is nil, then answer a 1 x 1 black - form (a black dot)." - - | aForm | - form == nil - ifTrue: - [aForm := Form extent: 1 @ 1. - aForm fillBlack. - ^aForm] - ifFalse: - [^form]! Item was removed: - ----- Method: Path>>form: (in category 'accessing') ----- - form: aForm - "Make the argument, aForm, be the receiver's form." - - form := aForm! Item was removed: - ----- Method: Path>>initializeCollectionOfPoints (in category 'private') ----- - initializeCollectionOfPoints - - collectionOfPoints := OrderedCollection new! Item was removed: - ----- Method: Path>>initializeCollectionOfPoints: (in category 'private') ----- - initializeCollectionOfPoints: anInteger - - collectionOfPoints := OrderedCollection new: anInteger! Item was removed: - ----- Method: Path>>isEmpty (in category 'testing') ----- - isEmpty - - ^collectionOfPoints isEmpty! Item was removed: - ----- Method: Path>>last (in category 'accessing') ----- - last - "Answer the last point on the receiver's path; included to correspond to - OrderedCollection protocol." - - ^collectionOfPoints last! Item was removed: - ----- Method: Path>>offset (in category 'accessing') ----- - offset - "There are basically two kinds of display objects in the system: those - that, when asked to transform themselves, create a new object; and those - that side effect themselves by maintaining a record of the transformation - request (typically an offset). Path, like Rectangle and Point, is a display - object of the first kind." - - self shouldNotImplement! Item was removed: - ----- Method: Path>>removeAllSuchThat: (in category 'removing') ----- - removeAllSuchThat: aBlock - "Evaluate aBlock for each element of the receiver. - Remove each element for which aBlock evaluates to true." - - collectionOfPoints removeAllSuchThat: aBlock. - ! Item was removed: - ----- Method: Path>>scaleBy: (in category 'transforming') ----- - scaleBy: aPoint - "Answers a new Path scaled by aPoint. Does not affect the current data in - this Path." - - | newPath | - newPath := self species new: self size. - newPath form: self form. - collectionOfPoints do: [:element | newPath add: (element scaleBy: aPoint)]. - ^newPath! Item was removed: - ----- Method: Path>>secondPoint (in category 'accessing') ----- - secondPoint - "Answer the second element of the receiver." - - ^collectionOfPoints at: 2! Item was removed: - ----- Method: Path>>secondPoint: (in category 'accessing') ----- - secondPoint: aPoint - "Replace the second element of the receiver with the new value aPoint. - Answer the argument aPoint." - - collectionOfPoints at: 2 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Path>>select: (in category 'enumerating') ----- - select: aBlock - "Evaluate aBlock with each of the receiver's elements as the argument. - Collect into a new path like the receiver only those elements for which - aBlock evaluates to true. Answer the new path." - - | newCollection | - newCollection := collectionOfPoints select: aBlock. - newCollection form: self form. - ^newCollection! Item was removed: - ----- Method: Path>>size (in category 'accessing') ----- - size - "Answer the length of the receiver." - - ^collectionOfPoints size! Item was removed: - ----- Method: Path>>thirdPoint (in category 'accessing') ----- - thirdPoint - "Answer the third element of the receiver." - - ^collectionOfPoints at: 3! Item was removed: - ----- Method: Path>>thirdPoint: (in category 'accessing') ----- - thirdPoint: aPoint - "Replace the third element of the receiver with the new value aPoint. - Answer the argument aPoint." - - collectionOfPoints at: 3 put: aPoint. - ^aPoint! Item was removed: - ----- Method: Path>>translateBy: (in category 'transforming') ----- - translateBy: aPoint - "Answers a new Path whose elements are translated by aPoint. Does not - affect the elements of this Path." - - | newPath | - newPath := self species new: self size. - newPath form: self form. - collectionOfPoints do: [:element | newPath add: (element translateBy: aPoint)]. - ^newPath! Item was removed: - Path subclass: #Spline - instanceVariableNames: 'coefficients' - classVariableNames: '' - poolDictionaries: '' - category: 'ST80-Paths'! - - !Spline commentStamp: '' prior: 0! - I represent a collection of Points through which a cubic spline curve is fitted.! Item was removed: - ----- Method: Spline class>>example (in category 'examples') ----- - example - "Designate points on the Path by clicking the red button. Terminate by - pressing any other button. A curve will be displayed, through the - selected points, using a long black form." - - | splineCurve aForm flag| - aForm := Form extent: 2 at 2. - aForm fillBlack. - splineCurve := Spline new. - splineCurve form: aForm. - flag := true. - [flag] whileTrue: - [Sensor waitButton. - Sensor redButtonPressed - ifTrue: - [splineCurve add: Sensor waitButton. - Sensor waitNoButton. - aForm displayOn: Display at: splineCurve last] - ifFalse: [flag:=false]]. - splineCurve computeCurve. - splineCurve isEmpty - ifFalse: [splineCurve displayOn: Display. - Sensor waitNoButton]. - - "Spline example"! Item was removed: - ----- Method: Spline>>coefficients (in category 'accessing') ----- - coefficients - "Answer an eight-element Array of Arrays each of which is the length - of the receiver. The first four arrays are the values, first, second and - third derivatives, respectively, for the parametric spline in x. The last - four elements are for y." - - ^coefficients! Item was removed: - ----- Method: Spline>>computeCurve (in category 'displaying') ----- - computeCurve - "Compute an array for the coefficients." - - | length extras | - length := self size. - extras := 0. - coefficients := Array new: 8. - 1 to: 8 do: [:i | coefficients at: i put: (Array new: length + extras)]. - 1 to: 5 by: 4 do: - [:k | - 1 to: length do: - [:i | (coefficients at: k) - at: i put: (k = 1 - ifTrue: [(self at: i) x asFloat] - ifFalse: [(self at: i) y asFloat])]. - 1 to: extras do: [:i | (coefficients at: k) - at: length + i put: ((coefficients at: k) - at: i + 1)]. - self derivs: (coefficients at: k) - first: (coefficients at: k + 1) - second: (coefficients at: k + 2) - third: (coefficients at: k + 3)]. - extras > 0 - ifTrue: [1 to: 8 do: - [:i | - coefficients at: i put: ((coefficients at: i) - copyFrom: 2 to: length + 1)]]! Item was removed: - ----- Method: Spline>>derivs:first:second:third: (in category 'private') ----- - derivs: a first: point1 second: point2 third: point3 - "Compute the first, second and third derivitives (in coefficients) from - the Points in this Path (coefficients at: 1 and coefficients at: 5)." - - | l v anArray | - l := a size. - l < 2 ifTrue: [^self]. - l > 2 - ifTrue: - [v := Array new: l. - v at: 1 put: 4.0. - anArray := Array new: l. - anArray at: 1 put: (6.0 * ((a at: 1) - ((a at: 2) * 2.0) + (a at: 3))). - 2 to: l - 2 do: - [:i | - v at: i put: (4.0 - (1.0 / (v at: (i - 1)))). - anArray - at: i - put: (6.0 * ((a at: i) - ((a at: (i + 1)) * 2.0) + (a at: (i + 2))) - - ((anArray at: (i - 1)) / (v at: (i - 1))))]. - point2 at: (l - 1) put: ((anArray at: (l - 2)) / (v at: (l - 2))). - l - 2 to: 2 by: 0-1 do: - [:i | - point2 - at: i - put: ((anArray at: (i - 1)) - (point2 at: (i + 1)) / (v at: (i - 1)))]]. - point2 at: 1 put: (point2 at: l put: 0.0). - 1 to: l - 1 do: - [:i | point1 - at: i - put: ((a at: (i + 1)) - (a at: i) - - ((point2 at: i) * 2.0 + (point2 at: (i + 1)) / 6.0)). - point3 at: i put: ((point2 at: (i + 1)) - (point2 at: i))]! Item was removed: - ----- Method: Spline>>displayOn:at:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm - "Display the receiver, a spline curve, approximated by straight line - segments." - - | n line t x y x1 x2 x3 y1 y2 y3 | - collectionOfPoints size < 1 ifTrue: [self error: 'a spline must have at least one point']. - line := Line new. - line form: self form. - line beginPoint: - (x := (coefficients at: 1) at: 1) rounded @ (y := (coefficients at: 5) at: 1) rounded. - 1 to: (coefficients at: 1) size - 1 do: - [:i | - "taylor series coefficients" - x1 := (coefficients at: 2) at: i. - y1 := (coefficients at: 6) at: i. - x2 := ((coefficients at: 3) at: i) / 2.0. - y2 := ((coefficients at: 7) at: i) / 2.0. - x3 := ((coefficients at: 4) at: i) / 6.0. - y3 := ((coefficients at: 8) at: i) / 6.0. - "guess n" - n := 5 max: (x2 abs + y2 abs * 2.0 + ((coefficients at: 3) - at: i + 1) abs + ((coefficients at: 7) - at: i + 1) abs / 100.0) rounded. - 1 to: n - 1 do: - [:j | - t := j asFloat / n. - line endPoint: - (x3 * t + x2 * t + x1 * t + x) rounded - @ (y3 * t + y2 * t + y1 * t + y) rounded. - line - displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm. - line beginPoint: line endPoint]. - line beginPoint: - (x := (coefficients at: 1) at: i + 1) rounded - @ (y := (coefficients at: 5) at: i + 1) rounded. - line - displayOn: aDisplayMedium - at: aPoint - clippingBox: clipRect - rule: anInteger - fillColor: aForm]! Item was removed: - ----- Method: Spline>>displayOn:transformation:clippingBox:rule:fillColor: (in category 'displaying') ----- - displayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm - "Get the scaled and translated path of newKnots." - - | newKnots newSpline | - newKnots := aTransformation applyTo: self. - newSpline := Spline new. - newKnots do: [:knot | newSpline add: knot]. - newSpline form: self form. - newSpline - displayOn: aDisplayMedium - at: 0 @ 0 - clippingBox: clipRect - rule: anInteger - fillColor: aForm! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 9 12:59:58 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 9 Mar 2021 12:59:58 0000 Subject: [squeak-dev] The Inbox: Monticello-ct.737.mcz Message-ID: A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.737.mcz ==================== Summary ==================== Name: Monticello-ct.737 Author: ct Time: 9 March 2021, 1:59:56.826559 pm UUID: 697dc3bc-f4f7-3e43-b05d-d6a1f5fb421e Ancestors: Monticello-mt.736 Revises warnings shown before saving a version. In #checkForNewVersions, do not only check the current repository (e.g. inbox) but also the sink repository (e.g. trunk). Also generalizes the idea of sink repositories and resolve hard-coded repositores in Monticello-UI. =============== Diff against Monticello-mt.736 =============== Item was added: + ----- Method: MCRepository>>allSinkRepositories (in category 'accessing') ----- + allSinkRepositories + "If the workflow of the receiver requires to move new versions into one of any other repositories in the end, answer all these available sink repositories here." + + self = MCRepository inbox ifTrue: [ + ^ {MCRepository trunk. MCRepository treated}]. + + ^ Array empty! Item was added: + ----- Method: MCRepository>>defaultSinkRepository (in category 'accessing') ----- + defaultSinkRepository + "If the workflow of the receiver requires to move new versions into another repository in the end, answer this default sink repository here." + + self = MCRepository inbox ifTrue: [ + ^ MCRepository trunk]. + + ^ nil! Item was changed: ----- Method: MCRepositoryInspector>>save (in category 'actions') ----- save + + | targetRepository | + targetRepository := self pickRepository ifNil: [^ self]. + + (self repository allSinkRepositories includes: targetRepository) ifTrue: [ + self notify: (String streamContents: [:stream | + stream nextPutAll: 'Versions from this repository should only be moved, not copied.' translated. + (self repository isKindOf: MCHttpRepository) ifTrue: [ + stream space; nextPutAll: ('Instead, use the web interface via {1} to manage contributions.' translated format: {(Url absoluteFromText: self repository description) + path: ''; + downloadUrl})]. + stream cr; cr; nextPutAll: 'Do you want to proceed anyway?' withCRs translated])]. + + repository storeVersion: self version.! - self pickRepository ifNotNil: - [:repository | - (self repository = MCRepository inbox and: - [repository = MCRepository trunk or: [repository = MCRepository treated]]) ifTrue: - [self notify: 'Versions from the inbox should only be moved, not copied. Instead, use the web interface via source.squeak.org to manage inbox contributions.\\Do you want to proceed anyway?' translated withCRs]. - repository storeVersion: self version]! Item was changed: ----- Method: MCWorkingCopyBrowser>>checkForNewerVersions (in category 'actions') ----- checkForNewerVersions + | newer | newer := workingCopy possiblyNewerVersionsIn: self repository. + (newer notEmpty ==> [ + self confirm: ('{1}\\{2}\\{3}' withCRs translated format: { + 'CAUTION!! These versions in the repository may be newer:' translated. + (newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149. + 'Do you really want to save this version?' translated}) ]) + ifFalse: [^ false]. + + self repository defaultSinkRepository ifNotNil: [:sinkRepository | + newer := workingCopy possiblyNewerVersionsIn: sinkRepository. + (newer notEmpty ==> [ + self confirm: ('{1}\\{2}\\{3}' withCRs translated format: { + 'CAUTION!! These versions in the sink repository\({1})\may be newer:' withCRs translated format: {sinkRepository description}. + (newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149. + 'Do you really want to save this version?' translated}) ]) + ifFalse: [^ false]]. + + ^ true! - ^ newer isEmpty or: [ - self confirm: 'CAUTION!! These versions in the repository may be newer:', - String cr, ((newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149), String cr, - 'Do you really want to save this version?'].! From marcel.taeumel at hpi.de Tue Mar 9 13:05:58 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 14:05:58 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> References: <,> <,> <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> Message-ID: MathExtras might host low-level optimizations, as I exemplified: > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. Best, Marcel Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) Best, Christoph Von: Thiede, Christoph Gesendet: Dienstag, 9. März 2021 12:56:04 An: squeak-dev Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). [http://www.hpi.de/] Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers)   Magnitude     Number Math-Quantity   Integer (+ subclasses)   Fraction   ScaledDecimal Math-Analysis   Complex   Float (+ subclasses)   Quaternion Math-Geometry   Point   Line   Rectangle   Polygon   Path Math-Collections   Vector2 (from 3DTransform, CroquetGL, etc.)   Vector3   Vector4   Matrix2x3   Matrix4x4   VectorArray   ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 13:15:24 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 13:15:24 +0000 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> <,> , Message-ID: <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> Hi Marcel, maybe I have expressed myself incorrectly, please let me try to correct this: > 1. You do not like the name #do:upThrough:. Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order. And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. > 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-) > See below Nicolas' comments on #copyUpThrough: This one? > My advice would be to stick with those semantics as much as possible to avoid confusion*. Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 13:39:17 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result | aButton withAllOwners do: [:morph | result nextPut: morph color] upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier > a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas > a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners > collect: [:morph | morph color] > until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100) collect: [:x | x squared] where: [:x | x even] until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock | result supplier | supplier := self readStream. result := {} writeStream. [[supplier atEnd] whileFalse: [ | val | val := supplier next. (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)]. (untilBlock value: val) ifTrue: [^result contents]] ] value. ^result contents collect: colBlock until: untilBlock ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 13:18:31 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 13:18:31 +0000 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <,> <,> <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de>, Message-ID: <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:05:58 An: squeak-dev Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) MathExtras might host low-level optimizations, as I exemplified: > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. Best, Marcel Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 9. März 2021 12:56:04 An: squeak-dev Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers) Magnitude Number Math-Quantity Integer (+ subclasses) Fraction ScaledDecimal Math-Analysis Complex Float (+ subclasses) Quaternion Math-Geometry Point Line Rectangle Polygon Path Math-Collections Vector2 (from 3DTransform, CroquetGL, etc.) Vector3 Vector4 Matrix2x3 Matrix4x4 VectorArray ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 13:22:47 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 14:22:47 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> References: <,> <,> <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <,> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again.  Best, Marcel Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) [http://www.hpi.de/] Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:05:58 An: squeak-dev Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   MathExtras might host low-level optimizations, as I exemplified: > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. Best, Marcel Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) Best, Christoph Von: Thiede, Christoph Gesendet: Dienstag, 9. März 2021 12:56:04 An: squeak-dev Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). [http://www.hpi.de/] Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers)   Magnitude     Number Math-Quantity   Integer (+ subclasses)   Fraction   ScaledDecimal Math-Analysis   Complex   Float (+ subclasses)   Quaternion Math-Geometry   Point   Line   Rectangle   Polygon   Path Math-Collections   Vector2 (from 3DTransform, CroquetGL, etc.)   Vector3   Vector4   Matrix2x3   Matrix4x4   VectorArray   ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 13:23:54 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 13:23:54 +0000 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com>, Message-ID: +1 for preventing "2 second" from answering "1 second", too confusing. -1 for answering "2 seconds" for "2 second", that would be very ambiguous language and grammatically incorrect. :-) I think we should either go with an assertion (self assert: self = 1) or deprecate the singular selectors altogether. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Chris Muller Gesendet: Dienstag, 9. März 2021 05:53:10 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Explorer / Inspector bug? My expectation would be that #second, #minute, #hour etc would be syntactic sugar. And I certainly would not expect "5 second" to mean one second duration. I note that we have several methods like this (second, minute, hour...) and they have Brent Pinkney's (brp) initials since 2004. I don't know if anyone depends on that existing behavior. That's correct. Brent adopted those methods from my MaTimeObjects package (which is still installable from SqueakMap), although in my version it didn't even account for the sign, it was always just ^ 1 second, regardless of the receiver. I agree they should just be synonyms. Off topic, but there are other problems with these duration methods. They are defined in Number but round the duration magnitudes to whole seconds. Where do you see that? I just tried "1.5 hours" and it worked... And durations for 1 day or 1 week are undefinable due to daylight savings transitions and occasional leap seconds. True, from a literal sense, but by that assessment we would have similar "problems" with ChronologyConstants' DaysInMonth, MicrosecondsInDay, OneDay, SecondsInDay, SecondsInHour, and SecondsInMinute. All are useful, nonetheless. - Chris -------------- next part -------------- An HTML attachment was scrubbed... URL: From Das.Linux at gmx.de Tue Mar 9 13:26:05 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Tue, 9 Mar 2021 14:26:05 +0100 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> Message-ID: <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> > On 9. Mar 2021, at 14:23, Thiede, Christoph wrote: > > +1 for preventing "2 second" from answering "1 second", too confusing. yes > -1 for answering "2 seconds" for "2 second", that would be very ambiguous language and grammatically incorrect. :-) no. "I want a two second delay" is perfectly valid :D -t > > I think we should either go with an assertion (self assert: self = 1) or deprecate the singular selectors altogether. > > Best, > Christoph > Von: Squeak-dev im Auftrag von Chris Muller > Gesendet: Dienstag, 9. März 2021 05:53:10 > An: The general-purpose Squeak developers list > Betreff: Re: [squeak-dev] Explorer / Inspector bug? > > My expectation would be that #second, #minute, #hour etc would > be syntactic sugar. And I certainly would not expect "5 second" > to mean one second duration. > > I note that we have several methods like this (second, minute, hour...) > and they have Brent Pinkney's (brp) initials since 2004. I don't know > if anyone depends on that existing behavior. > > That's correct. Brent adopted those methods from my MaTimeObjects package (which is still installable from SqueakMap), although in my version it didn't even account for the sign, it was always just ^ 1 second, regardless of the receiver. I agree they should just be synonyms. > > Off topic, but there are other problems with these duration methods. > They are defined in Number but round the duration magnitudes to > whole seconds. > > Where do you see that? I just tried "1.5 hours" and it worked... > > And durations for 1 day or 1 week are undefinable > due to daylight savings transitions and occasional leap seconds. > > True, from a literal sense, but by that assessment we would have similar "problems" with ChronologyConstants' DaysInMonth, MicrosecondsInDay, OneDay, SecondsInDay, SecondsInHour, and SecondsInMinute. All are useful, nonetheless. > > - Chris From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 13:26:58 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 13:26:58 +0000 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <,> <,> <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <,> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de>, Message-ID: >From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:22:47 An: squeak-dev Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again. Best, Marcel Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:05:58 An: squeak-dev Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) MathExtras might host low-level optimizations, as I exemplified: > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. Best, Marcel Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 9. März 2021 12:56:04 An: squeak-dev Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers) Magnitude Number Math-Quantity Integer (+ subclasses) Fraction ScaledDecimal Math-Analysis Complex Float (+ subclasses) Quaternion Math-Geometry Point Line Rectangle Polygon Path Math-Collections Vector2 (from 3DTransform, CroquetGL, etc.) Vector3 Vector4 Matrix2x3 Matrix4x4 VectorArray ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 13:28:37 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 14:28:37 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <,> <,> <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <,> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> <,> Message-ID: > non-ultimate partition The system evolves. Code changes. New insights will influence onward refactorings. That's always the baseline. ;-) Best, Marcel Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : >From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:22:47 An: squeak-dev Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again.  Best, Marcel Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) [http://www.hpi.de/] Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:05:58 An: squeak-dev Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   MathExtras might host low-level optimizations, as I exemplified: > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. Best, Marcel Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) Best, Christoph Von: Thiede, Christoph Gesendet: Dienstag, 9. März 2021 12:56:04 An: squeak-dev Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   Hi Marcel, sounds interesting! I have a few thoughts regarding package dependencies. As far as I understand, the dependency structure would look kind like this: Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) Math-Collections would probably depend on all other packages? The question is which of these dependencies can be eliminated and which are a problem at all. What about Random? Do you want to keep it in Kernel, depending on Math? What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). [http://www.hpi.de/] Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 10:50:09 An: squeak-dev Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes)   Hi all! I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. Please take a look at the following proposed classification: Kernel-Objects (= not Kernel-Numbers)   Magnitude     Number Math-Quantity   Integer (+ subclasses)   Fraction   ScaledDecimal Math-Analysis   Complex   Float (+ subclasses)   Quaternion Math-Geometry   Point   Line   Rectangle   Polygon   Path Math-Collections   Vector2 (from 3DTransform, CroquetGL, etc.)   Vector3   Vector4   Matrix2x3   Matrix4x4   VectorArray   ... It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) Best, Marcel Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : Hi everyone, during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. Bests Patrick # Squeak Change Proposal - Geometry Package ## Why? Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). ## Scope The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: - Point - Line - LineSegment - Polygon - Rectangle (as an optimization as it could be represented as a special Polygon already) Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. ### Affected classes: - All classes in ST80-Paths - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) - Rectangle, Quadrangle, Point (Graphics-Primitives) - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) ## Open questions - Should this become a single new package or a subcategory in the Graphics package? - Should the package contain an Ellipses class? - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? ## Risks - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 13:34:21 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 14:34:21 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> References: <1615235931986-0.post@n4.nabble.com> <,> <,> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> Message-ID: > And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols. It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part. > I do like the verbs and the prepositions, just not the order of keywords Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example: Array streamContents: [:result |    aButton withAllOwners       upThrough: [:morph| morph isSystemWindow]       do: [:morph | result nextPut: morph color]]. Best, Marcel Am 09.03.2021 14:15:33 schrieb Thiede, Christoph : Hi Marcel, maybe I have expressed myself incorrectly, please let me try to correct this: > 1. You do not like the name #do:upThrough:. Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order. And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. > 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-) > See below Nicolas' comments on #copyUpThrough: This one? > My advice would be to stick with those semantics as much as possible to avoid confusion*. Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 13:39:17 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result |    aButton withAllOwners       do: [:morph | result nextPut: morph color]       upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners >    collect: [:morph | morph color] >    until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100)         collect: [:x | x squared]         where: [:x | x even]         until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock         | result supplier |         supplier := self readStream.         result := {} writeStream.         [[supplier atEnd]             whileFalse: [ | val |               val := supplier next.               (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)].               (untilBlock value: val) ifTrue: [^result contents]]         ] value.         ^result contents collect: colBlock until: untilBlock         ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock         ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html [http://forum.world.st/Squeak-Dev-f45488.html] -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 13:47:49 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 13:47:49 +0000 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> , <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> Message-ID: <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> > "I want a two second delay" is perfectly valid :D Maybe a native English speaker can correct me but afaik, in the grammar dependency tree of "two-second delay", "two-second" is not an independent noun but a pre-modifying phrase only. Shall we really start to support even more different types of words in an object-oriented language like Smalltalk? Imho, substantives and verbs are already enough. :-) Otherwise, we might end up with overcomplicated expressions such as "2 seconds later do: [self flash. Wait for: 1.5 hour delay. self flash]". Exaggerating, of course. Though syntactically valid Smalltalk, definitively not "our" flavor of Smalltalk ... Reminds me rather of questionary constructs such as in RSpec (Ruby), for example. And if this argument is way too complex, here is even a simpler one: According to Grammarly, "two second delay" is not even valid English. It needs to be "two-second delay" and I have never heard of mapping grammatical hyphens to separate messages in Smalltalk languages before. But would like to read some examples if there are any. :-) Lbnl, I think it causes a lot of confusion and the need for coding styles if we create multiple selectors that do the same thing ... #ifNil:ifNotNil: vs #ifNil:ifNotNilDo:/#ifEmpty:ifNotEmpty: vs #ifEmpty:ifNotEmptyDo: is already hard enough. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Tobias Pape Gesendet: Dienstag, 9. März 2021 14:26:05 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Explorer / Inspector bug? > On 9. Mar 2021, at 14:23, Thiede, Christoph wrote: > > +1 for preventing "2 second" from answering "1 second", too confusing. yes > -1 for answering "2 seconds" for "2 second", that would be very ambiguous language and grammatically incorrect. :-) no. "I want a two second delay" is perfectly valid :D -t > > I think we should either go with an assertion (self assert: self = 1) or deprecate the singular selectors altogether. > > Best, > Christoph > Von: Squeak-dev im Auftrag von Chris Muller > Gesendet: Dienstag, 9. März 2021 05:53:10 > An: The general-purpose Squeak developers list > Betreff: Re: [squeak-dev] Explorer / Inspector bug? > > My expectation would be that #second, #minute, #hour etc would > be syntactic sugar. And I certainly would not expect "5 second" > to mean one second duration. > > I note that we have several methods like this (second, minute, hour...) > and they have Brent Pinkney's (brp) initials since 2004. I don't know > if anyone depends on that existing behavior. > > That's correct. Brent adopted those methods from my MaTimeObjects package (which is still installable from SqueakMap), although in my version it didn't even account for the sign, it was always just ^ 1 second, regardless of the receiver. I agree they should just be synonyms. > > Off topic, but there are other problems with these duration methods. > They are defined in Number but round the duration magnitudes to > whole seconds. > > Where do you see that? I just tried "1.5 hours" and it worked... > > And durations for 1 day or 1 week are undefinable > due to daylight savings transitions and occasional leap seconds. > > True, from a literal sense, but by that assessment we would have similar "problems" with ChronologyConstants' DaysInMonth, MicrosecondsInDay, OneDay, SecondsInDay, SecondsInHour, and SecondsInMinute. All are useful, nonetheless. > > - Chris -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 13:51:51 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 13:51:51 +0000 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> <,> <,> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de>, Message-ID: <8638e562727748cbbe25ee38a967b1b8@student.hpi.uni-potsdam.de> > Maybe #upThrough:do: would work? Here is an example: Definitively better than #do:upThrough:. :-) Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:34:21 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... > And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part. > I do like the verbs and the prepositions, just not the order of keywords Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example: Array streamContents: [:result | aButton withAllOwners upThrough: [:morph| morph isSystemWindow] do: [:morph | result nextPut: morph color]]. Best, Marcel Am 09.03.2021 14:15:33 schrieb Thiede, Christoph : Hi Marcel, maybe I have expressed myself incorrectly, please let me try to correct this: > 1. You do not like the name #do:upThrough:. Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order. And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. > 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-) > See below Nicolas' comments on #copyUpThrough: This one? > My advice would be to stick with those semantics as much as possible to avoid confusion*. Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 13:39:17 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result | aButton withAllOwners do: [:morph | result nextPut: morph color] upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier > a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas > a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners > collect: [:morph | morph color] > until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100) collect: [:x | x squared] where: [:x | x even] until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock | result supplier | supplier := self readStream. result := {} writeStream. [[supplier atEnd] whileFalse: [ | val | val := supplier next. (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)]. (untilBlock value: val) ifTrue: [^result contents]] ] value. ^result contents collect: colBlock until: untilBlock ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 14:01:51 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 15:01:51 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <8638e562727748cbbe25ee38a967b1b8@student.hpi.uni-potsdam.de> References: <1615235931986-0.post@n4.nabble.com> <,> <,> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> <,> <8638e562727748cbbe25ee38a967b1b8@student.hpi.uni-potsdam.de> Message-ID: > Thus my proposal to reuse the verb "select" [...] Hmm... maybe "detect" is what we could re-use as a word? Then, again, I totally forgot that a stream's #upTo: does not accept a predicate but just an object.  And so should #upThrough:. Hmpf.  #selectUpThrough:thenDo: #selectUpTo:thenDo: Bah. This is so wordy. -.-" Best, Marcel Am 09.03.2021 14:52:00 schrieb Thiede, Christoph : > Maybe #upThrough:do: would work? Here is an example: Definitively better than #do:upThrough:. :-) Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ... Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:34:21 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   > And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols. It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part. > I do like the verbs and the prepositions, just not the order of keywords Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example: Array streamContents: [:result |    aButton withAllOwners       upThrough: [:morph| morph isSystemWindow]       do: [:morph | result nextPut: morph color]]. Best, Marcel Am 09.03.2021 14:15:33 schrieb Thiede, Christoph : Hi Marcel, maybe I have expressed myself incorrectly, please let me try to correct this: > 1. You do not like the name #do:upThrough:. Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order. And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. > 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-) > See below Nicolas' comments on #copyUpThrough: This one? > My advice would be to stick with those semantics as much as possible to avoid confusion*. Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 13:39:17 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result |    aButton withAllOwners       do: [:morph | result nextPut: morph color]       upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners >    collect: [:morph | morph color] >    until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100)         collect: [:x | x squared]         where: [:x | x even]         until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock         | result supplier |         supplier := self readStream.         result := {} writeStream.         [[supplier atEnd]             whileFalse: [ | val |               val := supplier next.               (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)].               (untilBlock value: val) ifTrue: [^result contents]]         ] value.         ^result contents collect: colBlock until: untilBlock         ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock         ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html [http://forum.world.st/Squeak-Dev-f45488.html] -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 9 14:06:34 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 9 Mar 2021 15:06:34 +0100 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> <,> <,> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> <,> <8638e562727748cbbe25ee38a967b1b8@student.hpi.uni-potsdam.de> Message-ID: Maybe I will just do this from now on: aButton withAllOwners in: [:list | (list first: (list findFirst: [:m | m isSystemWindow])) collect: [:m | m color]] Best, Marcel Am 09.03.2021 15:01:51 schrieb Marcel Taeumel : > Thus my proposal to reuse the verb "select" [...] Hmm... maybe "detect" is what we could re-use as a word? Then, again, I totally forgot that a stream's #upTo: does not accept a predicate but just an object.  And so should #upThrough:. Hmpf.  #selectUpThrough:thenDo: #selectUpTo:thenDo: Bah. This is so wordy. -.-" Best, Marcel Am 09.03.2021 14:52:00 schrieb Thiede, Christoph : > Maybe #upThrough:do: would work? Here is an example: Definitively better than #do:upThrough:. :-) Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ... Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:34:21 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   > And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency  with the existing protocols. It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part. > I do like the verbs and the prepositions, just not the order of keywords Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example: Array streamContents: [:result |    aButton withAllOwners       upThrough: [:morph| morph isSystemWindow]       do: [:morph | result nextPut: morph color]]. Best, Marcel Am 09.03.2021 14:15:33 schrieb Thiede, Christoph : Hi Marcel, maybe I have expressed myself incorrectly, please let me try to correct this: > 1. You do not like the name #do:upThrough:. Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order. And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. > 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-) > See below Nicolas' comments on #copyUpThrough: This one? > My advice would be to stick with those semantics as much as possible to avoid confusion*. Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 13:39:17 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ...   Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result |    aButton withAllOwners       do: [:morph | result nextPut: morph color]       upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners >    collect: [:morph | morph color] >    until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100)         collect: [:x | x squared]         where: [:x | x even]         until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock         | result supplier |         supplier := self readStream.         result := {} writeStream.         [[supplier atEnd]             whileFalse: [ | val |               val := supplier next.               (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)].               (untilBlock value: val) ifTrue: [^result contents]]         ] value.         ^result contents collect: colBlock until: untilBlock         ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock         ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html [http://forum.world.st/Squeak-Dev-f45488.html] -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 14:23:58 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 14:23:58 +0000 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> <,> <,> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> <,> <8638e562727748cbbe25ee38a967b1b8@student.hpi.uni-potsdam.de> , Message-ID: <8b0affef6ddb4c37a4b412cda68592b6@student.hpi.uni-potsdam.de> > Hmm... maybe "detect" is what we could re-use as a word? "detect" is already being abused today IMO. I don't like #detect(Max|Min|Sum): because my general understanding of detection is to iterate until something specific is found. Or go the Python way (probably also used in other languages?) and support multiple semantics of the "upTo:"/"upThrough:" argument in the same selector. So both would work: #(1 2 3) upTo: 2. #(1 2 3) upTo: [:x | x isEven]. But I don't like this approach myself, because what should this one return then? #(notEven even maybeEven) upTo: #isEven. So I would be fine with #selectUpTo:thenDo: ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 15:06:34 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Maybe I will just do this from now on: aButton withAllOwners in: [:list | (list first: (list findFirst: [:m | m isSystemWindow])) collect: [:m | m color]] Best, Marcel Am 09.03.2021 15:01:51 schrieb Marcel Taeumel : > Thus my proposal to reuse the verb "select" [...] Hmm... maybe "detect" is what we could re-use as a word? Then, again, I totally forgot that a stream's #upTo: does not accept a predicate but just an object. And so should #upThrough:. Hmpf. #selectUpThrough:thenDo: #selectUpTo:thenDo: Bah. This is so wordy. -.-" Best, Marcel Am 09.03.2021 14:52:00 schrieb Thiede, Christoph : > Maybe #upThrough:do: would work? Here is an example: Definitively better than #do:upThrough:. :-) Still, I hope that no one will assume that "upThrough:" takes a number as "upTo:" does. Thus my proposal to reuse the verb "select" which has always been used in collection with predicate blocks ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 14:34:21 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... > And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. It is not a two-phase operation. It is just a #do: that stops at a certain point. It does not compare to #select:thenCollect:. It just constrains the enumeration part. > I do like the verbs and the prepositions, just not the order of keywords Well, there is #withIndexDo:. Maybe #upThrough:do: would work? Here is an example: Array streamContents: [:result | aButton withAllOwners upThrough: [:morph| morph isSystemWindow] do: [:morph | result nextPut: morph color]]. Best, Marcel Am 09.03.2021 14:15:33 schrieb Thiede, Christoph : Hi Marcel, maybe I have expressed myself incorrectly, please let me try to correct this: > 1. You do not like the name #do:upThrough:. Partially. :-) I do like the verbs and the prepositions, just not the order of keywords. I would prefer not to end up with a language like SQL where you need to read from the right to the left because the notion order of FROM and SELECT differs from their execution order. And since the proposed operation would actually be a two-phase operation by concept, I proposed to insert the little adverb "then" to improve consistency with the existing protocols. > 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. No, these were only for a long-term perspective. I would be absolutely fine with adding #selectUpThrough:thenDo: only, today. :-) > See below Nicolas' comments on #copyUpThrough: This one? > My advice would be to stick with those semantics as much as possible to avoid confusion*. Is this really the way to go? If we always add a new vocabulary when an existing one creates doubts, I fear this could hinder us from designing a simple and consistent language in the end. Rather, we should discuss the existing verbs and unify them if necessary. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 13:39:17 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi Christoph, let me try to summarize your thoughts: 1. You do not like the name #do:upThrough:. 2. You do not agree with just adding the #do:*-version but would like to go "all in" to also support #select* and #collect* and maybe even adapt the #take* protocol. Yeah, I disagree with you on both. :-) See below Nicolas' comments on #copyUpThrough: maybe also my thoughts on "baby steps" ;-) in my previous answer Best, Marcel Am 09.03.2021 13:23:16 schrieb Thiede, Christoph : Hi Marcel, I would pay additional attention to the order of arguments. :-) #do:upThrough: reads to me as: First do something for every element, then select all elements (which elements? the original elements or a collected copy?) as long as they do not meet a requirement. Which probably would not be the idea of this selector since it would be unnecessarily slow, wouldn't it? What would (1 to: 10) do: [:ea | self inform: ea] upThrough: [:ea | false] do? Show zero, one, or ten dialogs? In the following assuming that the right answer is zero ...: I think #selectUpThrough:thenDo: and #selectUpThrough:thenCollect: might fit better. Or maybe #takeUpThrough:... instead. It communicates the order of block execution more transparently and would be consistent and colocated to the existing #select:then[Do|Collect]: methods. What do you think? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 9. März 2021 09:40:38 An: squeak-dev Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... Hi all. I like the use of "upThrough" vs. "upTo" to distinguish inclusive from exclusive. Like the existing #copyUpThrough:. (So, not "until".) I think that #readStream should not be used in any collection's method (implementation). Instead, we now about #size and sometimes #array, so we should use #do: and similar. Or at least *try* not use it. Yes, I know about #streamContents:, which I think is really valuable. Even if we would add something like #collect:upThrough: or #collect:upTo:, I would not want to change the implementation of #collect:. Maybe use #collect: to implement the new interface, but not change it. An [:each | false] would just involve too many redundant checks. Considering the order of predicates, I would just support first-order predicates for now because that's what our most recent use cases would need. :-) *** All in all, I would suggest to just add #do:upThrough: and #do:upTo: to Sequenceable collection as well as #upThrough: to (Positionable)Stream. Let's not over-engineer this for now but see where such increment leads us. Then, my example use from the beginning could look like this: Array streamContents: [:result | aButton withAllOwners do: [:morph | result nextPut: morph color] upThrough: [:morph | morph isSystemWindow]]. Maybe, at a later point, we could evaluate the need for extending #reject:, #select:, #collect:, too. Maybe. What do you think? Best, Marcel Am 09.03.2021 08:07:23 schrieb Nicolas Cellier : Also the question of inclusion will arise as well as the order of predicates... There could also be symetrical once: [:x | x > 10]. Le lun. 8 mars 2021 à 23:33, Nicolas Cellier > a écrit : I like that, it's beginning to be expressive, even better than clojure. However, i think that clojure offers composable predicates thanks to lazyness... like Xtreams. Le lun. 8 mars 2021 à 21:38, Jaromir Matas > a écrit : > I am looking for something like #collect:until: or #upToSatisfying:. I do want the stop element to be included here, not sure about the general case. > > aButton withAllOwners > collect: [:morph | morph color] > until: [:morph | morph isSystemWindow]. > Hi again, ahh so you're actually looking for a generalized collect for any SequencableCollection or Stream :) Like this? (1 to: 100) collect: [:x | x squared] where: [:x | x even] until: [:x | x squared = 2500] collect: collectBlock where: whereBlock until: untilBlock | result supplier | supplier := self readStream. result := {} writeStream. [[supplier atEnd] whileFalse: [ | val | val := supplier next. (whereBlock value: val) ifTrue: [result nextPut: (collectBlock value: val)]. (untilBlock value: val) ifTrue: [^result contents]] ] value. ^result contents collect: colBlock until: untilBlock ^self collect: colBlock where: [:each | true] until: untilBlock or even: collect: colBlock ^self collect: colBlock until: [:each | true] ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 9 14:40:16 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 9 Mar 2021 14:40:16 +0000 Subject: [squeak-dev] The Inbox: Morphic-ct.1733.mcz In-Reply-To: References: , Message-ID: <0bf90153be354d5b835921a5889c3bbd@student.hpi.uni-potsdam.de> Hi Marcel, most editors support both ways through configuration. I fear that's stuff for a principal debate, just like "tabs vs spaces" ... So let the games begin! :D Most methods in Squeak are formatted with empty lines indented just like their surrounding lines, and this also matches my own preference. This has a number of advantages: 1. It's just more consistent that every line that is part of a logic unit (e.g. block, expression, or array) is indented in the same way, without defining any special treatments for empty lines. 2. If you fill an empty line with some statement, the indentation is already there and you do not need to correct (i.e. add) it. 3. If you remove a statement from an empty line, you do not need to "correct" (i.e. remove) the indentation. 4. It's easier to navigate through all lines with the caret because it does not jump back to the unintended beginning of a line. 5. Auto-generation is easier because we don't have an edge case for empty lines. But I know that the party of the "no-empty-indenters" also has at least one counterargument because they call these indentations trailing whitespace. > Note that "actually empty" would translate to "single indent/tab" in Squeak because of the way method source code is presented. And here's where the special treatments (cf. arg 1 above) would begin. If every line in a method (except the signature) has a minimum indentation of one, why should empty lines deserve a negative indentation of 1 compared to the default? If you have a method like this where the default indentation is effectively 2, why should empty lines only be intended with 1 tab? treat: something something ifNotNil: [ something foo. something bar. something baz]. For these reasons, I think indenting every line consistently would just be more consistent. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Montag, 8. März 2021 10:55:19 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Morphic-ct.1733.mcz Note that "actually empty" would translate to "single indent/tab" in Squeak because of the way method source code is presented. Best, Marcel Am 08.03.2021 10:52:54 schrieb Marcel Taeumel : Hi Christoph, why is this a bug? A quick experiment in Sublime Text suggested that this might be the expected behavior. At least for actually empty lines, having not a single white-space character. Best, Marcle Am 07.03.2021 20:43:09 schrieb commits at source.squeak.org : Christoph Thiede uploaded a new version of Morphic to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1733.mcz ==================== Summary ==================== Name: Morphic-ct.1733 Author: ct Time: 7 March 2021, 8:42:45.180906 pm UUID: b8246d49-b132-40af-8ad4-7428c544390c Ancestors: Morphic-mt.1731 Fixes an eternity-old bug in TextEditor which skipped empty lines when indenting/outdenting the selection. =============== Diff against Morphic-mt.1731 =============== Item was changed: ----- Method: TextEditor>>inOutdent:delta: (in category 'editing keys') ----- inOutdent: aKeyboardEvent delta: delta "Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw" | realStart realStop lines startLine stopLine start stop adjustStart "indentation" numLines oldText newText newSize | - "Operate on entire lines, but remember the real selection for re-highlighting later" realStart := self startIndex. realStop := self stopIndex - 1. "Special case a caret on a line of its own, including weird case at end of paragraph" (realStart > realStop and: [realStart < 2 or: [(paragraph string at: realStart - 1) == Character cr or: [(paragraph string at: realStart - 1) == Character lf]]]) ifTrue: [delta < 0 ifTrue: [morph flash] ifFalse: [self replaceSelectionWith: Character tab asText. self selectAt: realStart + 1]. ^true]. lines := paragraph lines. startLine := paragraph lineIndexOfCharacterIndex: realStart. "start on a real line, not a wrapped line" [startLine = 1 or: [CharacterSet crlf includes: (paragraph string at: (lines at: startLine-1) last)]] whileFalse: [startLine := startLine - 1]. stopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop). start := (lines at: startLine) first. stop := (lines at: stopLine) last. "Pin the start of highlighting unless the selection starts a line" adjustStart := realStart > start. "Find the indentation of the least-indented non-blank line; never outdent more" "indentation := (startLine to: stopLine) inject: 1000 into: [:m :l | m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])]. indentation + delta <= 0 ifTrue: [^false]." numLines := stopLine + 1 - startLine. oldText := paragraph text copyFrom: start to: stop. newText := oldText species new: oldText size + ((numLines * delta) max: 0). "Do the actual work" newSize := 0. delta > 0 ifTrue: [| tabs | tabs := oldText species new: delta withAll: Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | + newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1. - startL < endWithoutDelimiters ifTrue: [newText replaceFrom: 1 + newSize to: (newSize := newSize + delta) with: tabs startingAt: 1]. newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - startL) with: oldText startingAt: startL]] ifFalse: [| tab | tab := Character tab. oldText string lineIndicesDo: [:startL :endWithoutDelimiters :endL | | i | i := 0. [i + delta < 0 and: [ i + startL <= endWithoutDelimiters and: [(oldText at: i + startL) == tab]]] whileTrue: [i := i + 1]. newText replaceFrom: 1 + newSize to: (newSize := 1 + newSize + endL - (i + startL)) with: oldText startingAt: i + startL]]. newSize < newText size ifTrue: [newText := newText copyFrom: 1 to: newSize]. "Adjust the range that will be highlighted later" adjustStart ifTrue: [realStart := (realStart + delta) max: start]. realStop := realStop + newSize - oldText size. "Replace selection" self selectInvisiblyFrom: start to: stop. self replaceSelectionWith: newText. self selectFrom: realStart to: realStop. "highlight only the original range" ^ true! -------------- next part -------------- An HTML attachment was scrubbed... URL: From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 9 17:33:24 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 9 Mar 2021 11:33:24 -0600 (CST) Subject: [squeak-dev] find original change set In-Reply-To: References: Message-ID: <1615311204604-0.post@n4.nabble.com> Hi all, oldest thread I've been replying to so far ever. :D While refactoring the VersionBrowser's annotations, I just found out that ChangeRecord>>#originalChangeSetForSelector: is broken because, in my fresh Trunk image, all ~1800 MethodChangeRecord instances have nil as currentMethod. The comment in the relevant setter is kind of confusing ...: MethodChangeRecord>>noteNewMethod: newMethod "NEVER do this. It is evil." currentMethod := nil. Why is this? After searching the mailing archive for a while, I did not only find the attached message describing the same problem but also an obsolete fragment from the ReleaseBuilder: "The pointer to currentMethod is not realy needed (anybody care to fix this) and often holds on to obsolete bindings" MethodChangeRecord allInstancesDo: [:each | each noteNewMethod: nil]. But with regard to the present bug, I dare to say: currentMethod is needed again, because without, #originalChangeSetForSelector: won't be able to identify the correct method by its position in the changes file. So why is currentMethod evil? I assume it just would blow up your image significantly. But I'd like to repair the changeset search. There are only two other users of currentMethod, #compileAll:from: and #invokePhase1, which are both defined on ClassChangeRecord and do not have any eventual senders in the Trunk, so they could probably be deprecated? If this is correct, my proposal would be as follows: Remove the currentMethod inst var from MethodChangeRecord, add a position instvar instead, and adjust #noteNewMethod: and #containsMethodAtPosition: accordingly. Does this sound reasonable to you? It is safe to assume that the position of a CompiledMethod instance will not change again unless the sources file is updated? I would be glad about your help! Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From nicolas.cellier.aka.nice at gmail.com Tue Mar 9 17:49:29 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Tue, 9 Mar 2021 18:49:29 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: Wow, high level of brainstorming, not sure I can catch up ;) I'm not sure whether Number subclasses should be put in Math, they are so essential to the Kernel... What could obviously go in some extra Math-something is for example all the function extensions (inverse trigonometry, hyperbolic, ...) For trigonometry, not sure, it's essential to geometry. Also the accelerated large integer arithmetic would find its place in some extra package (not required in Kernel). No problem if you want Quaternion in trunk, if it can be useful for 3D geometry, then good. For RawBitArray, I'm not sure, it's more specific to programming than math per se (the fact that we use bounded integers of some byte-size...). RawBitsArray really shine when interacting with the outside world (importing large data sets from some standard format and/or passing them to FFI). Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : > > > non-ultimate partition > > The system evolves. Code changes. New insights will influence onward refactorings. That's always the baseline. ;-) > > Best, > Marcel > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) > > > Best, > > Christoph > > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:22:47 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again. > > Best, > Marcel > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:05:58 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > MathExtras might host low-level optimizations, as I exemplified: > > > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. > > Best, > Marcel > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... > > Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) > > > Best, > > Christoph > > ________________________________ > Von: Thiede, Christoph > Gesendet: Dienstag, 9. März 2021 12:56:04 > An: squeak-dev > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > > Hi Marcel, > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > As far as I understand, the dependency structure would look kind like this: > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) > > Math-Collections would probably depend on all other packages? > > > The question is which of these dependencies can be eliminated and which are a problem at all. > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? > > In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 10:50:09 > An: squeak-dev > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > Hi all! > > I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. > > Please take a look at the following proposed classification: > > Kernel-Objects (= not Kernel-Numbers) > Magnitude > Number > > Math-Quantity > Integer (+ subclasses) > Fraction > ScaledDecimal > > Math-Analysis > Complex > Float (+ subclasses) > Quaternion > > Math-Geometry > Point > Line > Rectangle > Polygon > Path > > Math-Collections > Vector2 (from 3DTransform, CroquetGL, etc.) > Vector3 > Vector4 > Matrix2x3 > Matrix4x4 > VectorArray > ... > > It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) > > Best, > Marcel > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : > > Hi everyone, > > during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. > > In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. > > Bests > Patrick > > # Squeak Change Proposal - Geometry Package > > ## Why? > Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). > > ## Scope > The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: > - Point > - Line > - LineSegment > - Polygon > - Rectangle (as an optimization as it could be represented as a special Polygon already) > > Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. > > ### Affected classes: > - All classes in ST80-Paths > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > - Rectangle, Quadrangle, Point (Graphics-Primitives) > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) > > ## Open questions > - Should this become a single new package or a subcategory in the Graphics package? > - Should the package contain an Ellipses class? > - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? > > ## Risks > - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) > - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. > > From craig at blackpagedigital.com Wed Mar 10 03:31:37 2021 From: craig at blackpagedigital.com (Craig Latta) Date: Tue, 9 Mar 2021 19:31:37 -0800 Subject: [squeak-dev] =?utf-8?q?California_Smalltalkers_March_2021=3A_Hern?= =?utf-8?q?=C3=A1n_Wilkinson_on_LiveTyping=2C_a_type_system_for_Smalltalk?= Message-ID: Greetings! Please join us online at the Wednesday, 10 March 2021 gathering of California Smalltalkers, for a presentation by Hernán Wilkinson on LiveTyping, a type system for Smalltalk. Details at https://meetup.com/california-smalltalkers/. cheers, Dan Ingalls, Vanessa Freudenberg, and Craig Latta -- Craig Latta :: research computer scientist Black Page Digital :: Berkeley, California 663137D7940BF5C0AFC :: 1349FB2ADA32C4D5314CE From marcel.taeumel at hpi.de Wed Mar 10 08:48:10 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 10 Mar 2021 09:48:10 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: Hi Nicolas, in the long term, we might want to re-design the entire "Kernel" perspective to be specialized attachments to other packages. I would like to see a clear separation of non-programming, high-level concepts and technical, low-level optimizations. For example, "Integer" could be discoverable through "Math-Quantity" while "SmallInteger" could reside in "MathExtras-Kernel" or similar. Eventually, we would turn around the perspective from primarily technical to primarily conceptual. Note that the inheritance tree would still look the same. Another example would consider RawBitsArray. "Rectangle" could reside in "Math-Geometry" while "Float32Rectangle" could be a subclass of "Float32Array" and hence reside in "MathExtras-Collections" or similar, optimized for FFI. A similar example can be constructed for "Quanternion" and "Float32Quaternion". Best, Marcel Am 09.03.2021 18:49:55 schrieb Nicolas Cellier : Wow, high level of brainstorming, not sure I can catch up ;) I'm not sure whether Number subclasses should be put in Math, they are so essential to the Kernel... What could obviously go in some extra Math-something is for example all the function extensions (inverse trigonometry, hyperbolic, ...) For trigonometry, not sure, it's essential to geometry. Also the accelerated large integer arithmetic would find its place in some extra package (not required in Kernel). No problem if you want Quaternion in trunk, if it can be useful for 3D geometry, then good. For RawBitArray, I'm not sure, it's more specific to programming than math per se (the fact that we use bounded integers of some byte-size...). RawBitsArray really shine when interacting with the outside world (importing large data sets from some standard format and/or passing them to FFI). Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : > > > non-ultimate partition > > The system evolves. Code changes. New insights will influence onward refactorings. That's always the baseline. ;-) > > Best, > Marcel > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) > > > Best, > > Christoph > > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:22:47 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again. > > Best, > Marcel > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:05:58 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > MathExtras might host low-level optimizations, as I exemplified: > > > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. > > Best, > Marcel > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... > > Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) > > > Best, > > Christoph > > ________________________________ > Von: Thiede, Christoph > Gesendet: Dienstag, 9. März 2021 12:56:04 > An: squeak-dev > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > > Hi Marcel, > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > As far as I understand, the dependency structure would look kind like this: > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) > > Math-Collections would probably depend on all other packages? > > > The question is which of these dependencies can be eliminated and which are a problem at all. > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? > > In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 10:50:09 > An: squeak-dev > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > Hi all! > > I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. > > Please take a look at the following proposed classification: > > Kernel-Objects (= not Kernel-Numbers) > Magnitude > Number > > Math-Quantity > Integer (+ subclasses) > Fraction > ScaledDecimal > > Math-Analysis > Complex > Float (+ subclasses) > Quaternion > > Math-Geometry > Point > Line > Rectangle > Polygon > Path > > Math-Collections > Vector2 (from 3DTransform, CroquetGL, etc.) > Vector3 > Vector4 > Matrix2x3 > Matrix4x4 > VectorArray > ... > > It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) > > Best, > Marcel > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : > > Hi everyone, > > during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. > > In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. > > Bests > Patrick > > # Squeak Change Proposal - Geometry Package > > ## Why? > Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). > > ## Scope > The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: > - Point > - Line > - LineSegment > - Polygon > - Rectangle (as an optimization as it could be represented as a special Polygon already) > > Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. > > ### Affected classes: > - All classes in ST80-Paths > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > - Rectangle, Quadrangle, Point (Graphics-Primitives) > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) > > ## Open questions > - Should this become a single new package or a subcategory in the Graphics package? > - Should the package contain an Ellipses class? > - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? > > ## Risks > - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) > - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicolas.cellier.aka.nice at gmail.com Wed Mar 10 10:22:03 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Wed, 10 Mar 2021 11:22:03 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: Hi Marcel, I see the POV of classification for understanding and teaching. But isn't there also the perspective of re-constructing a system from minimal core/kernel ? Also, is SmallInteger really related to Math? I do not see it as a specialization, but rather as providing some kernel operations (primitives) onto which we can build/generalize Integer math. Le mer. 10 mars 2021 à 09:48, Marcel Taeumel a écrit : > Hi Nicolas, > > in the long term, we might want to re-design the entire "Kernel" > perspective to be specialized attachments to other packages. I would like > to see a clear separation of non-programming, high-level concepts and > technical, low-level optimizations. > > For example, "Integer" could be discoverable through "Math-Quantity" while > "SmallInteger" could reside in "MathExtras-Kernel" or similar. Eventually, > we would turn around the perspective from primarily technical to primarily > conceptual. Note that the inheritance tree would still look the same. > > Another example would consider RawBitsArray. "Rectangle" could reside in > "Math-Geometry" while "Float32Rectangle" could be a subclass of > "Float32Array" and hence reside in "MathExtras-Collections" or similar, > optimized for FFI. > > A similar example can be constructed for "Quanternion" and > "Float32Quaternion". > > Best, > Marcel > > Am 09.03.2021 18:49:55 schrieb Nicolas Cellier < > nicolas.cellier.aka.nice at gmail.com>: > Wow, high level of brainstorming, not sure I can catch up ;) > > I'm not sure whether Number subclasses should be put in Math, they are > so essential to the Kernel... > > What could obviously go in some extra Math-something is for example > all the function extensions (inverse trigonometry, hyperbolic, ...) > For trigonometry, not sure, it's essential to geometry. > Also the accelerated large integer arithmetic would find its place in > some extra package (not required in Kernel). > No problem if you want Quaternion in trunk, if it can be useful for 3D > geometry, then good. > > For RawBitArray, I'm not sure, it's more specific to programming than > math per se (the fact that we use bounded integers of some > byte-size...). RawBitsArray really shine when interacting with the > outside world (importing large data sets from some standard format > and/or passing them to FFI). > > Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : > > > > > non-ultimate partition > > > > The system evolves. Code changes. New insights will influence onward > refactorings. That's always the baseline. ;-) > > > > Best, > > Marcel > > > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > > > From the perspective of "good old baby steps" and with the notion of > "Extras" as a non-ultimate partition in mind, this sounds very reasonable > ... :-) > > > > > > Best, > > > > Christoph > > > > ________________________________ > > Von: Squeak-dev im Auftrag von Taeumel, Marcel > > Gesendet: Dienstag, 9. März 2021 14:22:47 > > An: squeak-dev > > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: > Geometry Classes) > > > > First step would be to assess whether something is "core or not". And > "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. > Once a "MathExtras" package severely lacks cohesion, we can split it up > again. > > > > Best, > > Marcel > > > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary > to me. If you cannot find a precise name for a package, how high can its > coherency be? :-) > > > > > > Best, > > Christoph > > ________________________________ > > Von: Squeak-dev im Auftrag von Taeumel, Marcel > > Gesendet: Dienstag, 9. März 2021 14:05:58 > > An: squeak-dev > > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: > Geometry Classes) > > > > MathExtras might host low-level optimizations, as I exemplified: > > > > > And I would like to add that "number crunching" part around fancy > graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe > "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > > > :-) I assume that it may be beneficial to at least decide whether > something is "core" or "extra". I would like to have this for "Math" from > the beginning. > > > > Best, > > Marcel > > > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > > > Referring to the MathExtras proposal ... What is your general idea of an > extra package? I know Morphic-Extras as a collection of non-necessary > tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > > > > CollectionsExtras would be a place for Text enhancements such as > attributes (so actually, we could also call it simply "TextSupport" or > something like this), MathExtras would contain "math stuff that is not > necessary" ... > > > > Do you have any more precise idea of what classifies an extra package or > would "MathSmorgasbord" be a franker name for the package? If yes, this > would make me think about the coherency of such a package ... Just my 2 > cents, of course. :) > > > > > > Best, > > > > Christoph > > > > ________________________________ > > Von: Thiede, Christoph > > Gesendet: Dienstag, 9. März 2021 12:56:04 > > An: squeak-dev > > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: > Geometry Classes) > > > > > > Hi Marcel, > > > > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > > > > As far as I understand, the dependency structure would look kind like > this: > > > > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for > example), Math-Analysis (see senders of #asFloat for example) > > > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of > #asFloat) > > > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of > SmallInteger), Math-Analysis (see senders of #asFloat) > > > > Math-Collections would probably depend on all other packages? > > > > > > The question is which of these dependencies can be eliminated and which > are a problem at all. > > > > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > > > > What is about dependencies from Number (Kernel-Objects) to Float > (Math-Analysis), for example, #asFloat, but also sophisticated things such > as #sin? Do we want to create a bunch of extension methods for this? > > > > In any case, I think the "math functions" protocol on Collection should > become an extension protocol ("*Math-Analysis" or > "*Math-Analysis-enumerating"). > > > > > > Best, > > Christoph > > ________________________________ > > Von: Squeak-dev im Auftrag von Taeumel, Marcel > > Gesendet: Dienstag, 9. März 2021 10:50:09 > > An: squeak-dev > > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: > Geometry Classes) > > > > Hi all! > > > > I think that we would rather need a "Math" package with "Math-Geometry" > being one of multiple categories. > > > > Please take a look at the following proposed classification: > > > > Kernel-Objects (= not Kernel-Numbers) > > Magnitude > > Number > > > > Math-Quantity > > Integer (+ subclasses) > > Fraction > > ScaledDecimal > > > > Math-Analysis > > Complex > > Float (+ subclasses) > > Quaternion > > > > Math-Geometry > > Point > > Line > > Rectangle > > Polygon > > Path > > > > Math-Collections > > Vector2 (from 3DTransform, CroquetGL, etc.) > > Vector3 > > Vector4 > > Matrix2x3 > > Matrix4x4 > > VectorArray > > ... > > > > It would involve some effort, especially to untangle "ST80-Paths" from > graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" > and "Quaternion" in Trunk. And I would like to add that "number crunching" > part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" > or maybe "MathExtras-Collections", looking at all the subclasses of > RawBitsArray. > > > > May I add "Math" and "MathExtras" packages so that we can slowly get > started? :-) > > > > Best, > > Marcel > > > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : > > > > Hi everyone, > > > > during some recent clean-up an issue with geometry objects came up. As a > result the following idea came up which I thereby would like to put out for > an initial discussion. > > > > In case we find that this might be useful, I would continue by > implementing a first prototype of the package as a foundation of a more > in-depth discussion later on. > > > > Bests > > Patrick > > > > # Squeak Change Proposal - Geometry Package > > > > ## Why? > > Squeak implements basic geometry logic in too many different places. For > example intersection of different kinds of geometric objects is implemented > all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive > scattering across packages and classes impedes modularity, that is, > readability and extensibility. An example for this recently came up when we > discovered an issue with testing for graphical intersections between > PolygonMorph and RectangleMorph. It was not possible to compute that > overlapping area because the class Rectangle omits to provide an important > method. A quick fix would entail unnecessary dependencies (here: Morphic -> > Balloon) or duplicated code (see also > http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to > modularize the geometry objects and operations. As a side effect, dependent > packages such as Morphic can be simplified a little bit (more). > > > > ## Scope > > The proposed package should cover basic 2D geometric objects and their > operations represented by the following classes: > > - Point > > - Line > > - LineSegment > > - Polygon > > - Rectangle (as an optimization as it could be represented as a special > Polygon already) > > > > Most classes could simply be moved from their previous packages. > Afterwards the interfaces would need to be made consistent with each other > to allow interoperability of all geometry classes within the new package. > > > > ### Affected classes: > > - All classes in ST80-Paths > > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > > - Rectangle, Quadrangle, Point (Graphics-Primitives) > > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent > (Etoys-Squeakland-Graphics-Tools-Intersection) > > > > ## Open questions > > - Should this become a single new package or a subcategory in the > Graphics package? > > - Should the package contain an Ellipses class? > > - Should we model curved line segments as BezierLineSegments, > CurvedLineSegment, or Arc? > > > > ## Risks > > - This would potentially deprecate the existing ST80 geometry classes > (ST80-Paths) > > - Some of the new classes will cause name clashes with existing classes. > For example Line is currently in ST-80 and represents a line segment, and > the class LineSegment is a line segment but not in the geometric sense as > it also incorporates arcs. Both names might then be used by new classes > with different meanings. This might be mitigated by introducing a > pre-/postfix for the names of the new classes. > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Wed Mar 10 10:30:11 2021 From: m at jaromir.net (Jaromir Matas) Date: Wed, 10 Mar 2021 04:30:11 -0600 (CST) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> Message-ID: <1615372211711-0.post@n4.nabble.com> Hi Christoph, I'd like to recommend to use the fixed #isTerminated: (it's not in the Trunk yet because it can be done nicer but this one is at least working ok). isTerminated "Answer if the receiver is terminated, or at least terminating." self isActiveProcess ifTrue: [^ false]. ^suspendedContext isNil or: ["If the suspendedContext is the bottomContext and the pc is at the endPC, then there is nothing more to do." suspendedContext isBottomContext and: [suspendedContext pc >= suspendedContext endPC or: [suspendedContext closure isNil and: [suspendedContext methodClass == Process and: [suspendedContext selector == #terminate]]]]] Originally I noticed the bug on a nonsensical example but in your scenario it also plays a role! Some processes will be rightly considered terminated and disappear from Process Browser (#runUntilErrorOrReturnFrom among others, in my scenarios). It seems to me after `ctxt restart` the thread never returns back so the assignment is moot? At any rate it seems to me the problem is not related to non-local returns exclusively. Other scenario I have now: x:=nil. [self error: 'x1'] ensure: [[self error: 'x2'] ensure: [[self error: 'x3'] ensure: [x:=3]. x:=2]. x:=1]. x Unfortunately I've got to run now but I'll continue investigating tomorrow. Very interesting! :) Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Wed Mar 10 10:45:13 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 10 Mar 2021 11:45:13 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: That's right. I recall that Patrick's initial proposal was about reducing redundant implementations, most of them rather high-level. (One reason why "Number" would remain in "Kernel" is that "Character" inherits from it. And "DateAndTime" is a "Magnitude". Hmmm...) Hmm... so, if "Integer" would be in a "Math", would it make sense to keep "SmallInteger" in a "Kernel" package? I wouldn't have a problem with "eternally coupling" both Kernel and Math. Hmm.... For simplicity, let me focus on "SmallInteger" and "Float32Array" as two low-level optimizations. A minimal core needs minimal concepts, which should definitely include "Math" but maybe not "MathExtras"? After all, what value would a minimal core have if it cannot be used for anything meaningful? Then again, "anything meaningful" is so subjective ... Sigh. Mayber numbers aren't the best way to think about re-classification since most of them are used through literals and simple textual representations. Users do not bother with their classes. Hmmm... back to "Geometry" again, I guess. :-) Point, Rectangle, Line, Polygon, ... Best, Marcel Am 10.03.2021 11:22:23 schrieb Nicolas Cellier : Hi Marcel, I see the POV of classification for understanding and teaching. But isn't there also the perspective of re-constructing a system from minimal core/kernel ? Also, is SmallInteger really related to Math? I do not see it as a specialization, but rather as providing some kernel operations (primitives) onto which we can build/generalize Integer math. Le mer. 10 mars 2021 à 09:48, Marcel Taeumel a écrit : Hi Nicolas, in the long term, we might want to re-design the entire "Kernel" perspective to be specialized attachments to other packages. I would like to see a clear separation of non-programming, high-level concepts and technical, low-level optimizations. For example, "Integer" could be discoverable through "Math-Quantity" while "SmallInteger" could reside in "MathExtras-Kernel" or similar. Eventually, we would turn around the perspective from primarily technical to primarily conceptual. Note that the inheritance tree would still look the same. Another example would consider RawBitsArray. "Rectangle" could reside in "Math-Geometry" while "Float32Rectangle" could be a subclass of "Float32Array" and hence reside in "MathExtras-Collections" or similar, optimized for FFI. A similar example can be constructed for "Quanternion" and "Float32Quaternion". Best, Marcel Am 09.03.2021 18:49:55 schrieb Nicolas Cellier : Wow, high level of brainstorming, not sure I can catch up ;) I'm not sure whether Number subclasses should be put in Math, they are so essential to the Kernel... What could obviously go in some extra Math-something is for example all the function extensions (inverse trigonometry, hyperbolic, ...) For trigonometry, not sure, it's essential to geometry. Also the accelerated large integer arithmetic would find its place in some extra package (not required in Kernel). No problem if you want Quaternion in trunk, if it can be useful for 3D geometry, then good. For RawBitArray, I'm not sure, it's more specific to programming than math per se (the fact that we use bounded integers of some byte-size...). RawBitsArray really shine when interacting with the outside world (importing large data sets from some standard format and/or passing them to FFI). Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : > > > non-ultimate partition > > The system evolves. Code changes. New insights will influence onward refactorings. That's always the baseline. ;-) > > Best, > Marcel > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) > > > Best, > > Christoph > > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:22:47 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again. > > Best, > Marcel > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:05:58 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > MathExtras might host low-level optimizations, as I exemplified: > > > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. > > Best, > Marcel > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... > > Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) > > > Best, > > Christoph > > ________________________________ > Von: Thiede, Christoph > Gesendet: Dienstag, 9. März 2021 12:56:04 > An: squeak-dev > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > > Hi Marcel, > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > As far as I understand, the dependency structure would look kind like this: > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) > > Math-Collections would probably depend on all other packages? > > > The question is which of these dependencies can be eliminated and which are a problem at all. > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? > > In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 10:50:09 > An: squeak-dev > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > Hi all! > > I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. > > Please take a look at the following proposed classification: > > Kernel-Objects (= not Kernel-Numbers) > Magnitude > Number > > Math-Quantity > Integer (+ subclasses) > Fraction > ScaledDecimal > > Math-Analysis > Complex > Float (+ subclasses) > Quaternion > > Math-Geometry > Point > Line > Rectangle > Polygon > Path > > Math-Collections > Vector2 (from 3DTransform, CroquetGL, etc.) > Vector3 > Vector4 > Matrix2x3 > Matrix4x4 > VectorArray > ... > > It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) > > Best, > Marcel > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de [mailto:patrick.rein at hpi.uni-potsdam.de] : > > Hi everyone, > > during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. > > In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. > > Bests > Patrick > > # Squeak Change Proposal - Geometry Package > > ## Why? > Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872 [http://bugs.squeak.org/view.php?id=7872]). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). > > ## Scope > The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: > - Point > - Line > - LineSegment > - Polygon > - Rectangle (as an optimization as it could be represented as a special Polygon already) > > Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. > > ### Affected classes: > - All classes in ST80-Paths > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > - Rectangle, Quadrangle, Point (Graphics-Primitives) > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) > > ## Open questions > - Should this become a single new package or a subcategory in the Graphics package? > - Should the package contain an Ellipses class? > - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? > > ## Risks > - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) > - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Wed Mar 10 11:04:43 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 10 Mar 2021 12:04:43 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: > (One reason why "Number" would remain in "Kernel" is that "Character" inherits from it. And "DateAndTime" is a "Magnitude". Hmmm...) My bad. "Character" inherits from "Magnitude". Sorry for the confusion. Best, Marcel Am 10.03.2021 11:45:13 schrieb Marcel Taeumel : That's right. I recall that Patrick's initial proposal was about reducing redundant implementations, most of them rather high-level. (One reason why "Number" would remain in "Kernel" is that "Character" inherits from it. And "DateAndTime" is a "Magnitude". Hmmm...) Hmm... so, if "Integer" would be in a "Math", would it make sense to keep "SmallInteger" in a "Kernel" package? I wouldn't have a problem with "eternally coupling" both Kernel and Math. Hmm.... For simplicity, let me focus on "SmallInteger" and "Float32Array" as two low-level optimizations. A minimal core needs minimal concepts, which should definitely include "Math" but maybe not "MathExtras"? After all, what value would a minimal core have if it cannot be used for anything meaningful? Then again, "anything meaningful" is so subjective ... Sigh. Mayber numbers aren't the best way to think about re-classification since most of them are used through literals and simple textual representations. Users do not bother with their classes. Hmmm... back to "Geometry" again, I guess. :-) Point, Rectangle, Line, Polygon, ... Best, Marcel Am 10.03.2021 11:22:23 schrieb Nicolas Cellier : Hi Marcel, I see the POV of classification for understanding and teaching. But isn't there also the perspective of re-constructing a system from minimal core/kernel ? Also, is SmallInteger really related to Math? I do not see it as a specialization, but rather as providing some kernel operations (primitives) onto which we can build/generalize Integer math. Le mer. 10 mars 2021 à 09:48, Marcel Taeumel a écrit : Hi Nicolas, in the long term, we might want to re-design the entire "Kernel" perspective to be specialized attachments to other packages. I would like to see a clear separation of non-programming, high-level concepts and technical, low-level optimizations. For example, "Integer" could be discoverable through "Math-Quantity" while "SmallInteger" could reside in "MathExtras-Kernel" or similar. Eventually, we would turn around the perspective from primarily technical to primarily conceptual. Note that the inheritance tree would still look the same. Another example would consider RawBitsArray. "Rectangle" could reside in "Math-Geometry" while "Float32Rectangle" could be a subclass of "Float32Array" and hence reside in "MathExtras-Collections" or similar, optimized for FFI. A similar example can be constructed for "Quanternion" and "Float32Quaternion". Best, Marcel Am 09.03.2021 18:49:55 schrieb Nicolas Cellier : Wow, high level of brainstorming, not sure I can catch up ;) I'm not sure whether Number subclasses should be put in Math, they are so essential to the Kernel... What could obviously go in some extra Math-something is for example all the function extensions (inverse trigonometry, hyperbolic, ...) For trigonometry, not sure, it's essential to geometry. Also the accelerated large integer arithmetic would find its place in some extra package (not required in Kernel). No problem if you want Quaternion in trunk, if it can be useful for 3D geometry, then good. For RawBitArray, I'm not sure, it's more specific to programming than math per se (the fact that we use bounded integers of some byte-size...). RawBitsArray really shine when interacting with the outside world (importing large data sets from some standard format and/or passing them to FFI). Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : > > > non-ultimate partition > > The system evolves. Code changes. New insights will influence onward refactorings. That's always the baseline. ;-) > > Best, > Marcel > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) > > > Best, > > Christoph > > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:22:47 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again. > > Best, > Marcel > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:05:58 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > MathExtras might host low-level optimizations, as I exemplified: > > > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. > > Best, > Marcel > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... > > Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) > > > Best, > > Christoph > > ________________________________ > Von: Thiede, Christoph > Gesendet: Dienstag, 9. März 2021 12:56:04 > An: squeak-dev > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > > Hi Marcel, > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > As far as I understand, the dependency structure would look kind like this: > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) > > Math-Collections would probably depend on all other packages? > > > The question is which of these dependencies can be eliminated and which are a problem at all. > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? > > In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 10:50:09 > An: squeak-dev > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > Hi all! > > I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. > > Please take a look at the following proposed classification: > > Kernel-Objects (= not Kernel-Numbers) > Magnitude > Number > > Math-Quantity > Integer (+ subclasses) > Fraction > ScaledDecimal > > Math-Analysis > Complex > Float (+ subclasses) > Quaternion > > Math-Geometry > Point > Line > Rectangle > Polygon > Path > > Math-Collections > Vector2 (from 3DTransform, CroquetGL, etc.) > Vector3 > Vector4 > Matrix2x3 > Matrix4x4 > VectorArray > ... > > It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) > > Best, > Marcel > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de [mailto:patrick.rein at hpi.uni-potsdam.de] : > > Hi everyone, > > during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. > > In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. > > Bests > Patrick > > # Squeak Change Proposal - Geometry Package > > ## Why? > Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872 [http://bugs.squeak.org/view.php?id=7872]). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). > > ## Scope > The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: > - Point > - Line > - LineSegment > - Polygon > - Rectangle (as an optimization as it could be represented as a special Polygon already) > > Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. > > ### Affected classes: > - All classes in ST80-Paths > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > - Rectangle, Quadrangle, Point (Graphics-Primitives) > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) > > ## Open questions > - Should this become a single new package or a subcategory in the Graphics package? > - Should the package contain an Ellipses class? > - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? > > ## Risks > - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) > - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From duke.j.david at gmail.com Wed Mar 10 11:19:00 2021 From: duke.j.david at gmail.com (David Duke) Date: Wed, 10 Mar 2021 11:19:00 +0000 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: Interesting discussion. Throws up issues that I and possibly others have had getting started with Smalltalk in general. What are the criteria by which classes are arranged into categories? Leaving an element of subjective choice may be helpful, but some guidelines might not go amiss. Whilst the design choice of single inheritance for classes has been done to death. Is there any reason to restrict classes to a single category. After all its primary use I believe is as an aid to navigating the classes via inspectors. And there as been work on UIs for multi-dimensional data/hierarchies. Take 'Polygon' as an example I might expect to find it under: - graphics, where its primary uses are? - 2D Primitives? - geometry, as it supports geometric operations such as testing containment - Collections, as its a collection of points, and one might want to enumerate/select. etc `specific cases is an orthogonal issue. Is it useful to view rectangle/triangle etc a optimised forms of Polygon? Now if you look elsewhere - Java allows classes to have implement interfaces - Haskell allows types to be instances of multiple type classes? So why not allow classes to belong to multiple categories and/or categories to be connected via different kinds of links along the lines of concepts in a semantic network... In ay event it would be helpful if there were some general published guidelines for what membership of a category means any criteria for putting classes into categories or not and then for each category the defining characteristics of its classes? Just some thoughts.. regards, David. On Wed, Mar 10, 2021 at 10:45 AM Marcel Taeumel wrote: > That's right. I recall that Patrick's initial proposal was about reducing > redundant implementations, most of them rather high-level. > > (One reason why "Number" would remain in "Kernel" is that "Character" > inherits from it. And "DateAndTime" is a "Magnitude". Hmmm...) > > Hmm... so, if "Integer" would be in a "Math", would it make sense to keep > "SmallInteger" in a "Kernel" package? I wouldn't have a problem with > "eternally coupling" both Kernel and Math. Hmm.... > > For simplicity, let me focus on "SmallInteger" and "Float32Array" as two > low-level optimizations. A minimal core needs minimal concepts, which > should definitely include "Math" but maybe not "MathExtras"? After all, > what value would a minimal core have if it cannot be used for anything > meaningful? Then again, "anything meaningful" is so subjective ... Sigh. > Mayber numbers aren't the best way to think about re-classification since > most of them are used through literals and simple textual representations. > Users do not bother with their classes. > > Hmmm... back to "Geometry" again, I guess. :-) Point, Rectangle, Line, > Polygon, ... > > Best, > Marcel > > Am 10.03.2021 11:22:23 schrieb Nicolas Cellier < > nicolas.cellier.aka.nice at gmail.com>: > Hi Marcel, > I see the POV of classification for understanding and teaching. But isn't > there also the perspective of re-constructing a system from minimal > core/kernel ? > Also, is SmallInteger really related to Math? I do not see it as a > specialization, but rather as providing some kernel operations (primitives) > onto which we can build/generalize Integer math. > > Le mer. 10 mars 2021 à 09:48, Marcel Taeumel a > écrit : > >> Hi Nicolas, >> >> in the long term, we might want to re-design the entire "Kernel" >> perspective to be specialized attachments to other packages. I would like >> to see a clear separation of non-programming, high-level concepts and >> technical, low-level optimizations. >> >> For example, "Integer" could be discoverable through "Math-Quantity" >> while "SmallInteger" could reside in "MathExtras-Kernel" or similar. >> Eventually, we would turn around the perspective from primarily technical >> to primarily conceptual. Note that the inheritance tree would still look >> the same. >> >> Another example would consider RawBitsArray. "Rectangle" could reside in >> "Math-Geometry" while "Float32Rectangle" could be a subclass of >> "Float32Array" and hence reside in "MathExtras-Collections" or similar, >> optimized for FFI. >> >> A similar example can be constructed for "Quanternion" and >> "Float32Quaternion". >> >> Best, >> Marcel >> >> Am 09.03.2021 18:49:55 schrieb Nicolas Cellier < >> nicolas.cellier.aka.nice at gmail.com>: >> Wow, high level of brainstorming, not sure I can catch up ;) >> >> I'm not sure whether Number subclasses should be put in Math, they are >> so essential to the Kernel... >> >> What could obviously go in some extra Math-something is for example >> all the function extensions (inverse trigonometry, hyperbolic, ...) >> For trigonometry, not sure, it's essential to geometry. >> Also the accelerated large integer arithmetic would find its place in >> some extra package (not required in Kernel). >> No problem if you want Quaternion in trunk, if it can be useful for 3D >> geometry, then good. >> >> For RawBitArray, I'm not sure, it's more specific to programming than >> math per se (the fact that we use bounded integers of some >> byte-size...). RawBitsArray really shine when interacting with the >> outside world (importing large data sets from some standard format >> and/or passing them to FFI). >> >> Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : >> > >> > > non-ultimate partition >> > >> > The system evolves. Code changes. New insights will influence onward >> refactorings. That's always the baseline. ;-) >> > >> > Best, >> > Marcel >> > >> > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : >> > >> > From the perspective of "good old baby steps" and with the notion of >> "Extras" as a non-ultimate partition in mind, this sounds very reasonable >> ... :-) >> > >> > >> > Best, >> > >> > Christoph >> > >> > ________________________________ >> > Von: Squeak-dev im Auftrag von Taeumel, Marcel >> > Gesendet: Dienstag, 9. März 2021 14:22:47 >> > An: squeak-dev >> > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: >> Proposal: Geometry Classes) >> > >> > First step would be to assess whether something is "core or not". And >> "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. >> Once a "MathExtras" package severely lacks cohesion, we can split it up >> again. >> > >> > Best, >> > Marcel >> > >> > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : >> > >> > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary >> to me. If you cannot find a precise name for a package, how high can its >> coherency be? :-) >> > >> > >> > Best, >> > Christoph >> > ________________________________ >> > Von: Squeak-dev im Auftrag von Taeumel, Marcel >> > Gesendet: Dienstag, 9. März 2021 14:05:58 >> > An: squeak-dev >> > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: >> Proposal: Geometry Classes) >> > >> > MathExtras might host low-level optimizations, as I exemplified: >> > >> > > And I would like to add that "number crunching" part around fancy >> graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe >> "MathExtras-Collections", looking at all the subclasses of RawBitsArray. >> > >> > :-) I assume that it may be beneficial to at least decide whether >> something is "core" or "extra". I would like to have this for "Math" from >> the beginning. >> > >> > Best, >> > Marcel >> > >> > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : >> > >> > Referring to the MathExtras proposal ... What is your general idea of >> an extra package? I know Morphic-Extras as a collection of non-necessary >> tools, helpers, and demos, but the general idea sounds kind of vague to me. >> > >> > >> > CollectionsExtras would be a place for Text enhancements such as >> attributes (so actually, we could also call it simply "TextSupport" or >> something like this), MathExtras would contain "math stuff that is not >> necessary" ... >> > >> > Do you have any more precise idea of what classifies an extra package >> or would "MathSmorgasbord" be a franker name for the package? If yes, this >> would make me think about the coherency of such a package ... Just my 2 >> cents, of course. :) >> > >> > >> > Best, >> > >> > Christoph >> > >> > ________________________________ >> > Von: Thiede, Christoph >> > Gesendet: Dienstag, 9. März 2021 12:56:04 >> > An: squeak-dev >> > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: >> Proposal: Geometry Classes) >> > >> > >> > Hi Marcel, >> > >> > >> > sounds interesting! I have a few thoughts regarding package >> dependencies. >> > >> > >> > As far as I understand, the dependency structure would look kind like >> this: >> > >> > >> > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for >> example), Math-Analysis (see senders of #asFloat for example) >> > >> > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of >> #asFloat) >> > >> > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) >> > >> > Math-Geometry -> Kernel (of course), Math-Quantity (senders of >> SmallInteger), Math-Analysis (see senders of #asFloat) >> > >> > Math-Collections would probably depend on all other packages? >> > >> > >> > The question is which of these dependencies can be eliminated and which >> are a problem at all. >> > >> > >> > What about Random? Do you want to keep it in Kernel, depending on Math? >> > >> > >> > What is about dependencies from Number (Kernel-Objects) to Float >> (Math-Analysis), for example, #asFloat, but also sophisticated things such >> as #sin? Do we want to create a bunch of extension methods for this? >> > >> > In any case, I think the "math functions" protocol on Collection should >> become an extension protocol ("*Math-Analysis" or >> "*Math-Analysis-enumerating"). >> > >> > >> > Best, >> > Christoph >> > ________________________________ >> > Von: Squeak-dev im Auftrag von Taeumel, Marcel >> > Gesendet: Dienstag, 9. März 2021 10:50:09 >> > An: squeak-dev >> > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: >> Geometry Classes) >> > >> > Hi all! >> > >> > I think that we would rather need a "Math" package with "Math-Geometry" >> being one of multiple categories. >> > >> > Please take a look at the following proposed classification: >> > >> > Kernel-Objects (= not Kernel-Numbers) >> > Magnitude >> > Number >> > >> > Math-Quantity >> > Integer (+ subclasses) >> > Fraction >> > ScaledDecimal >> > >> > Math-Analysis >> > Complex >> > Float (+ subclasses) >> > Quaternion >> > >> > Math-Geometry >> > Point >> > Line >> > Rectangle >> > Polygon >> > Path >> > >> > Math-Collections >> > Vector2 (from 3DTransform, CroquetGL, etc.) >> > Vector3 >> > Vector4 >> > Matrix2x3 >> > Matrix4x4 >> > VectorArray >> > ... >> > >> > It would involve some effort, especially to untangle "ST80-Paths" from >> graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" >> and "Quaternion" in Trunk. And I would like to add that "number crunching" >> part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" >> or maybe "MathExtras-Collections", looking at all the subclasses of >> RawBitsArray. >> > >> > May I add "Math" and "MathExtras" packages so that we can slowly get >> started? :-) >> > >> > Best, >> > Marcel >> > >> > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : >> > >> > Hi everyone, >> > >> > during some recent clean-up an issue with geometry objects came up. As >> a result the following idea came up which I thereby would like to put out >> for an initial discussion. >> > >> > In case we find that this might be useful, I would continue by >> implementing a first prototype of the package as a foundation of a more >> in-depth discussion later on. >> > >> > Bests >> > Patrick >> > >> > # Squeak Change Proposal - Geometry Package >> > >> > ## Why? >> > Squeak implements basic geometry logic in too many different places. >> For example intersection of different kinds of geometric objects is >> implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such >> extensive scattering across packages and classes impedes modularity, that >> is, readability and extensibility. An example for this recently came up >> when we discovered an issue with testing for graphical intersections >> between PolygonMorph and RectangleMorph. It was not possible to compute >> that overlapping area because the class Rectangle omits to provide an >> important method. A quick fix would entail unnecessary dependencies (here: >> Morphic -> Balloon) or duplicated code (see also >> http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to >> modularize the geometry objects and operations. As a side effect, dependent >> packages such as Morphic can be simplified a little bit (more). >> > >> > ## Scope >> > The proposed package should cover basic 2D geometric objects and their >> operations represented by the following classes: >> > - Point >> > - Line >> > - LineSegment >> > - Polygon >> > - Rectangle (as an optimization as it could be represented as a special >> Polygon already) >> > >> > Most classes could simply be moved from their previous packages. >> Afterwards the interfaces would need to be made consistent with each other >> to allow interoperability of all geometry classes within the new package. >> > >> > ### Affected classes: >> > - All classes in ST80-Paths >> > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) >> > - Rectangle, Quadrangle, Point (Graphics-Primitives) >> > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent >> (Etoys-Squeakland-Graphics-Tools-Intersection) >> > >> > ## Open questions >> > - Should this become a single new package or a subcategory in the >> Graphics package? >> > - Should the package contain an Ellipses class? >> > - Should we model curved line segments as BezierLineSegments, >> CurvedLineSegment, or Arc? >> > >> > ## Risks >> > - This would potentially deprecate the existing ST80 geometry classes >> (ST80-Paths) >> > - Some of the new classes will cause name clashes with existing >> classes. For example Line is currently in ST-80 and represents a line >> segment, and the class LineSegment is a line segment but not in the >> geometric sense as it also incorporates arcs. Both names might then be used >> by new classes with different meanings. This might be mitigated by >> introducing a pre-/postfix for the names of the new classes. >> > >> > >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Wed Mar 10 11:23:14 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 10 Mar 2021 12:23:14 +0100 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: Hi Dave. Just a quick thought. :-) > Is there any reason to restrict classes to a single category. After all its primary use I believe is as an aid to navigating the classes via inspectors. Well, in this case, it matters big time whether one proposes something for the "Kernel" or just "MathExtras" package. One goal here is to level the path for such Trunk contributions. :-) Best, Marcel Am 10.03.2021 12:19:27 schrieb David Duke : Interesting discussion. Throws up issues that I and possibly others have had getting started with Smalltalk in general. What are the criteria by which classes are arranged into categories? Leaving an element of subjective choice may be helpful, but some guidelines might not go amiss. Whilst the design choice of single inheritance for classes has been done to death. Is there any reason to restrict classes to a single category. After all its primary use I believe is as an aid to navigating the classes via inspectors. And there as been work on UIs for multi-dimensional data/hierarchies. Take 'Polygon' as an example I might  expect to find it  under: - graphics, where its primary uses are? - 2D Primitives? - geometry, as it supports geometric operations such as testing containment - Collections, as its a collection of points, and one might want to enumerate/select.  etc `specific cases is an orthogonal issue. Is it useful to view rectangle/triangle etc a optimised forms of Polygon? Now if you look elsewhere  - Java allows classes to have implement  interfaces - Haskell allows types to be instances of multiple type classes? So why not allow classes to belong to multiple categories and/or categories to be connected via different kinds of links along the lines of concepts in a semantic network...  In ay event it would be helpful if there were some general published guidelines for what membership of a category means any  criteria for putting classes into categories or not and then for each category the defining characteristics of its classes? Just some thoughts.. regards, David. On Wed, Mar 10, 2021 at 10:45 AM Marcel Taeumel wrote: That's right. I recall that Patrick's initial proposal was about reducing redundant implementations, most of them rather high-level. (One reason why "Number" would remain in "Kernel" is that "Character" inherits from it. And "DateAndTime" is a "Magnitude". Hmmm...) Hmm... so, if "Integer" would be in a "Math", would it make sense to keep "SmallInteger" in a "Kernel" package? I wouldn't have a problem with "eternally coupling" both Kernel and Math. Hmm.... For simplicity, let me focus on "SmallInteger" and "Float32Array" as two low-level optimizations. A minimal core needs minimal concepts, which should definitely include "Math" but maybe not "MathExtras"? After all, what value would a minimal core have if it cannot be used for anything meaningful? Then again, "anything meaningful" is so subjective ... Sigh. Mayber numbers aren't the best way to think about re-classification since most of them are used through literals and simple textual representations. Users do not bother with their classes. Hmmm... back to "Geometry" again, I guess. :-) Point, Rectangle, Line, Polygon, ... Best, Marcel Am 10.03.2021 11:22:23 schrieb Nicolas Cellier : Hi Marcel, I see the POV of classification for understanding and teaching. But isn't there also the perspective of re-constructing a system from minimal core/kernel ? Also, is SmallInteger really related to Math? I do not see it as a specialization, but rather as providing some kernel operations (primitives) onto which we can build/generalize Integer math. Le mer. 10 mars 2021 à 09:48, Marcel Taeumel a écrit : Hi Nicolas, in the long term, we might want to re-design the entire "Kernel" perspective to be specialized attachments to other packages. I would like to see a clear separation of non-programming, high-level concepts and technical, low-level optimizations. For example, "Integer" could be discoverable through "Math-Quantity" while "SmallInteger" could reside in "MathExtras-Kernel" or similar. Eventually, we would turn around the perspective from primarily technical to primarily conceptual. Note that the inheritance tree would still look the same. Another example would consider RawBitsArray. "Rectangle" could reside in "Math-Geometry" while "Float32Rectangle" could be a subclass of "Float32Array" and hence reside in "MathExtras-Collections" or similar, optimized for FFI. A similar example can be constructed for "Quanternion" and "Float32Quaternion". Best, Marcel Am 09.03.2021 18:49:55 schrieb Nicolas Cellier : Wow, high level of brainstorming, not sure I can catch up ;) I'm not sure whether Number subclasses should be put in Math, they are so essential to the Kernel... What could obviously go in some extra Math-something is for example all the function extensions (inverse trigonometry, hyperbolic, ...) For trigonometry, not sure, it's essential to geometry. Also the accelerated large integer arithmetic would find its place in some extra package (not required in Kernel). No problem if you want Quaternion in trunk, if it can be useful for 3D geometry, then good. For RawBitArray, I'm not sure, it's more specific to programming than math per se (the fact that we use bounded integers of some byte-size...). RawBitsArray really shine when interacting with the outside world (importing large data sets from some standard format and/or passing them to FFI). Le mar. 9 mars 2021 à 14:28, Marcel Taeumel a écrit : > > > non-ultimate partition > > The system evolves. Code changes. New insights will influence onward refactorings. That's always the baseline. ;-) > > Best, > Marcel > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > From the perspective of "good old baby steps" and with the notion of "Extras" as a non-ultimate partition in mind, this sounds very reasonable ... :-) > > > Best, > > Christoph > > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:22:47 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > First step would be to assess whether something is "core or not". And "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. Once a "MathExtras" package severely lacks cohesion, we can split it up again. > > Best, > Marcel > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary to me. If you cannot find a precise name for a package, how high can its coherency be? :-) > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 14:05:58 > An: squeak-dev > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > MathExtras might host low-level optimizations, as I exemplified: > > > And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > :-) I assume that it may be beneficial to at least decide whether something is "core" or "extra". I would like to have this for "Math" from the beginning. > > Best, > Marcel > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > Referring to the MathExtras proposal ... What is your general idea of an extra package? I know Morphic-Extras as a collection of non-necessary tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > CollectionsExtras would be a place for Text enhancements such as attributes (so actually, we could also call it simply "TextSupport" or something like this), MathExtras would contain "math stuff that is not necessary" ... > > Do you have any more precise idea of what classifies an extra package or would "MathSmorgasbord" be a franker name for the package? If yes, this would make me think about the coherency of such a package ... Just my 2 cents, of course. :) > > > Best, > > Christoph > > ________________________________ > Von: Thiede, Christoph > Gesendet: Dienstag, 9. März 2021 12:56:04 > An: squeak-dev > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > > Hi Marcel, > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > As far as I understand, the dependency structure would look kind like this: > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for example), Math-Analysis (see senders of #asFloat for example) > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of #asFloat) > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of SmallInteger), Math-Analysis (see senders of #asFloat) > > Math-Collections would probably depend on all other packages? > > > The question is which of these dependencies can be eliminated and which are a problem at all. > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > What is about dependencies from Number (Kernel-Objects) to Float (Math-Analysis), for example, #asFloat, but also sophisticated things such as #sin? Do we want to create a bunch of extension methods for this? > > In any case, I think the "math functions" protocol on Collection should become an extension protocol ("*Math-Analysis" or "*Math-Analysis-enumerating"). > > > Best, > Christoph > ________________________________ > Von: Squeak-dev im Auftrag von Taeumel, Marcel > Gesendet: Dienstag, 9. März 2021 10:50:09 > An: squeak-dev > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) > > Hi all! > > I think that we would rather need a "Math" package with "Math-Geometry" being one of multiple categories. > > Please take a look at the following proposed classification: > > Kernel-Objects (= not Kernel-Numbers) > Magnitude > Number > > Math-Quantity > Integer (+ subclasses) > Fraction > ScaledDecimal > > Math-Analysis > Complex > Float (+ subclasses) > Quaternion > > Math-Geometry > Point > Line > Rectangle > Polygon > Path > > Math-Collections > Vector2 (from 3DTransform, CroquetGL, etc.) > Vector3 > Vector4 > Matrix2x3 > Matrix4x4 > VectorArray > ... > > It would involve some effort, especially to untangle "ST80-Paths" from graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" and "Quaternion" in Trunk. And I would like to add that "number crunching" part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > May I add "Math" and "MathExtras" packages so that we can slowly get started? :-) > > Best, > Marcel > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de [mailto:patrick.rein at hpi.uni-potsdam.de] : > > Hi everyone, > > during some recent clean-up an issue with geometry objects came up. As a result the following idea came up which I thereby would like to put out for an initial discussion. > > In case we find that this might be useful, I would continue by implementing a first prototype of the package as a foundation of a more in-depth discussion later on. > > Bests > Patrick > > # Squeak Change Proposal - Geometry Package > > ## Why? > Squeak implements basic geometry logic in too many different places. For example intersection of different kinds of geometric objects is implemented all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive scattering across packages and classes impedes modularity, that is, readability and extensibility. An example for this recently came up when we discovered an issue with testing for graphical intersections between PolygonMorph and RectangleMorph. It was not possible to compute that overlapping area because the class Rectangle omits to provide an important method. A quick fix would entail unnecessary dependencies (here: Morphic -> Balloon) or duplicated code (see also http://bugs.squeak.org/view.php?id=7872 [http://bugs.squeak.org/view.php?id=7872]). Consequently, we might want to modularize the geometry objects and operations. As a side effect, dependent packages such as Morphic can be simplified a little bit (more). > > ## Scope > The proposed package should cover basic 2D geometric objects and their operations represented by the following classes: > - Point > - Line > - LineSegment > - Polygon > - Rectangle (as an optimization as it could be represented as a special Polygon already) > > Most classes could simply be moved from their previous packages. Afterwards the interfaces would need to be made consistent with each other to allow interoperability of all geometry classes within the new package. > > ### Affected classes: > - All classes in ST80-Paths > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > - Rectangle, Quadrangle, Point (Graphics-Primitives) > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent (Etoys-Squeakland-Graphics-Tools-Intersection) > > ## Open questions > - Should this become a single new package or a subcategory in the Graphics package? > - Should the package contain an Ellipses class? > - Should we model curved line segments as BezierLineSegments, CurvedLineSegment, or Arc? > > ## Risks > - This would potentially deprecate the existing ST80 geometry classes (ST80-Paths) > - Some of the new classes will cause name clashes with existing classes. For example Line is currently in ST-80 and represents a line segment, and the class LineSegment is a line segment but not in the geometric sense as it also incorporates arcs. Both names might then be used by new classes with different meanings. This might be mitigated by introducing a pre-/postfix for the names of the new classes. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Wed Mar 10 16:49:03 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 10 Mar 2021 16:49:03 0000 Subject: [squeak-dev] The Inbox: System-ct.1222.mcz Message-ID: A new version of System was added to project The Inbox: http://source.squeak.org/inbox/System-ct.1222.mcz ==================== Summary ==================== Name: System-ct.1222 Author: ct Time: 10 March 2021, 5:48:57.099559 pm UUID: 17232cc7-2542-9046-87e0-0ff0033b09dd Ancestors: System-mt.1221 Adds alternative user initials of Igor Stasenko (Igor.Stasenko), found in a class comment. =============== Diff against System-mt.1221 =============== Item was changed: ----- Method: SystemNavigation class>>privateAuthorsRaw (in category 'class initialization') ----- (excessive size, no diff calculated) From commits at source.squeak.org Wed Mar 10 17:19:44 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 10 Mar 2021 17:19:44 0000 Subject: [squeak-dev] The Inbox: System-ct.1223.mcz Message-ID: A new version of System was added to project The Inbox: http://source.squeak.org/inbox/System-ct.1223.mcz ==================== Summary ==================== Name: System-ct.1223 Author: ct Time: 10 March 2021, 6:19:36.587559 pm UUID: 4d3c6ad5-a6b9-b44b-8145-87e91f5c90a2 Ancestors: System-mt.1221 Makes the extent of the annotation setup window dynamic. With the next annotation request that is added, the current space will be too small. =============== Diff against System-mt.1221 =============== Item was changed: ----- Method: Preferences class>>annotationEditingWindow (in category 'support - misc') ----- annotationEditingWindow "Answer a window affording editing of annotations" + | info standardHeight standardWidth aPanel ins outs current aWindow aButton | - | aPanel ins outs current aWindow aButton info standardHeight standardWidth | - standardHeight := 200. - standardWidth := (2 sqrt reciprocal * standardHeight) rounded. Smalltalk isMorphic ifFalse: [self error: 'annotations can be edited only in morphic']. + + info := self annotationInfo. + standardHeight := 20 * info size min: self currentWorld height * 0.8 max: 100. + standardWidth := (2 sqrt reciprocal * standardHeight) rounded. aPanel := AlignmentMorph newRow extent: 2 * standardWidth @ standardHeight. ins := AlignmentMorph newColumn extent: standardWidth @ standardHeight. ins color: Color green muchLighter. ins enableDrop: true; beSticky. outs := AlignmentMorph newColumn extent: standardWidth @ standardHeight. outs color: Color red muchLighter. outs enableDrop: true; beSticky. aPanel addMorph: outs; addMorphFront: ins. outs position: ins position + (standardWidth @ 0). current := self defaultAnnotationRequests. - info := self annotationInfo. current do: [:sym | | pair aMorph | pair := info detect: [:aPair | aPair first == sym]. aMorph := StringMorph new contents: pair first. aMorph setBalloonText: pair last. aMorph enableDrag: true. aMorph on: #startDrag send: #startDrag:with: to: aMorph. ins addMorphBack: aMorph]. info do: [:aPair | (current includes: aPair first) ifFalse: [| aMorph | aMorph := StringMorph new contents: aPair first. aMorph setBalloonText: aPair last. aMorph enableDrag: true. aMorph on: #startDrag send: #startDrag:with: to: aMorph. outs addMorph: aMorph]]. aPanel layoutChanged. aWindow := SystemWindowWithButton new setLabel: 'Annotations'. aButton := SimpleButtonMorph new target: Preferences; actionSelector: #acceptAnnotationsFrom:; arguments: (Array with: aWindow); label: 'apply'; borderWidth: 0; borderColor: Color transparent; color: Color transparent. aButton submorphs first color: Color blue. aButton setBalloonText: 'After moving all the annotations you want to the left (green) side, and all the ones you do NOT want to the right (pink) side, hit this "apply" button to have your choices take effect.'. aWindow buttonInTitle: aButton; adjustExtraButton. ^ aPanel wrappedInWindow: aWindow"Preferences annotationEditingWindow openInHand"! From commits at source.squeak.org Wed Mar 10 17:22:09 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 10 Mar 2021 17:22:09 0000 Subject: [squeak-dev] The Inbox: Monticello-ct.738.mcz Message-ID: A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.738.mcz ==================== Summary ==================== Name: Monticello-ct.738 Author: ct Time: 10 March 2021, 6:22:01.061559 pm UUID: 6401b50a-de37-1043-bd96-6821e9ab3434 Ancestors: Monticello-mt.736 Supports author name in and removes redundant spaces from the annotation string of a method definition. Kind of complements Tools-ct.1015, but is loadable stand-alone. =============== Diff against Monticello-mt.736 =============== Item was changed: ----- Method: MCMethodDefinition>>printAnnotations:on: (in category 'annotations') ----- printAnnotations: requests on: aStream "Add a string for an annotation pane, trying to fulfill the annotation requests. These might include anything that Preferences defaultAnnotationRequests might return. Which includes anything in Preferences annotationInfo To edit these, use:" "Preferences editAnnotations" + | annotations | + annotations := requests + collect: [:request | request + caseOf: { + [#timeStamp] -> [self timeStamp]. + [#author] -> [ + | initials | + initials := self timeStamp ifNotNil: [:timeStamp | + timeStamp findTokens ifNotEmpty: [:tokens | tokens first]]. + SystemNavigation authorsInverted + at: initials + ifPresent: [:fullNames | fullNames anyOne] + ifAbsent: ['unknown author' translated]]. + [#messageCategory] -> [self category]. + [#requirements] -> [self requirements joinSeparatedBy: Character space] } + otherwise: []] + thenSelect: [:annotation | annotation isEmptyOrNil not]. + + annotations + do: [:annotation | aStream nextPutAll: annotation] + separatedBy: [aStream space].! - requests do: [ :aRequest | - aRequest == #timeStamp ifTrue: [ aStream nextPutAll: self timeStamp ]. - aRequest == #messageCategory ifTrue: [ aStream nextPutAll: self category ]. - aRequest == #requirements ifTrue: [ - self requirements do: [ :req | - aStream nextPutAll: req ] separatedBy: [ aStream space ]]. - ] separatedBy: [ aStream space ].! From commits at source.squeak.org Wed Mar 10 17:26:50 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 10 Mar 2021 17:26:50 0000 Subject: [squeak-dev] The Inbox: Tools-ct.1031.mcz Message-ID: A new version of Tools was added to project The Inbox: http://source.squeak.org/inbox/Tools-ct.1031.mcz ==================== Summary ==================== Name: Tools-ct.1031 Author: ct Time: 10 March 2021, 6:26:41.374559 pm UUID: 90289614-021a-254a-b67f-5612c973d257 Ancestors: Tools-mt.1030 Fixes styling in change sorters if no real method is selected. No need to invoke Shout on messages such as "method was removed". Using an instance variable for this to avoid duplication of the contents logic. =============== Diff against Tools-mt.1030 =============== Item was changed: CodeHolder subclass: #ChangeSorter + instanceVariableNames: 'parent myChangeSet currentClassName currentSelector priorChangeSetList contentsAreStyleable' - instanceVariableNames: 'parent myChangeSet currentClassName currentSelector priorChangeSetList' classVariableNames: '' poolDictionaries: '' category: 'Tools-Changes'! + !ChangeSorter commentStamp: 'ct 3/10/2021 18:24' prior: 0! - !ChangeSorter commentStamp: 'wiz 2/3/2010 23:38' prior: 0! I display a ChangeSet. Two of me are in a DualChangeSorter. aStringOrNil Instance Variables currentClassName: currentSelector: myChangeSet: parent: priorChangeSetList: + contentsAreStyleable currentClassName - string parseable into class-name [class] [class trait] needs to be fitlered by (self withoutItemAnnotation: currentClassName) to remove pakaging note currentSelector - string parseable into selector-name needs to be fitlered by (self withoutItemAnnotation: currentSelector) to remove pakaging note myChangeSet - name of current changeset parent -the dual changesorter that contains this one. Used for dealing with the other half. priorChangeSetList + - holds the current change set list. Used to detect changes in list when a newly generated list no long match the prior list.! - - holds the current change set list. Used to detect changes in list when a newly generated list no long match the prior list. - ! Item was changed: ----- Method: ChangeSorter>>aboutToStyle: (in category 'code pane') ----- aboutToStyle: aStyler "This is a notification that aStyler is about to re-style its text. Set the classOrMetaClass in aStyler, so that identifiers will be resolved correctly. Answer true to allow styling to proceed, or false to veto the styling" + contentsAreStyleable ~= false ifFalse: [^false]. - self isModeStyleable ifFalse: [^false]. - self currentSelector ifNil: [^false]. aStyler classOrMetaClass: self selectedClassOrMetaClass. ^true! Item was changed: ----- Method: ChangeSorter>>setContents (in category 'code pane') ----- setContents "return the source code that shows in the bottom pane" | sel class strm changeType | self clearUserEditFlag. + contentsAreStyleable := false. myChangeSet ifNil: [^ contents := String empty]. "should not happen but can" currentClassName ifNil: [^ contents := myChangeSet preambleString ifNil: [String empty]]. class := self selectedClassOrMetaClass. (sel := self selectedMessageName) == nil ifFalse: [changeType := (myChangeSet atSelector: (sel := sel asSymbol) class: class). changeType == #remove ifTrue: [^ contents := 'Method has been removed (see versions)']. changeType == #addedThenRemoved ifTrue: [^ contents := 'Added then removed (see versions)']. class ifNil: [^ contents := 'Method was added, but cannot be found!!']. (class includesSelector: sel) ifFalse: [^ contents := 'Method was added, but cannot be found!!']. + contentsAreStyleable := true. contents := class sourceCodeAt: sel. (#(prettyPrint prettyDiffs) includes: contentsSymbol) ifTrue: [contents := class prettyPrinterClass format: contents in: class notifying: nil]. + self showingAnyKindOfDiffs ifTrue: [ + contentsAreStyleable := false. + contents := self diffFromPriorSourceFor: contents]. - self showingAnyKindOfDiffs - ifTrue: [contents := self diffFromPriorSourceFor: contents]. ^ contents := contents asText makeSelectorBoldIn: class] ifTrue: [strm := WriteStream on: (String new: 100). (myChangeSet classChangeAt: (self withoutItemAnnotation: currentClassName)) do: [:each | each = #remove ifTrue: [strm nextPutAll: 'Entire class was removed.'; cr]. each = #addedThenRemoved ifTrue: [strm nextPutAll: 'Class was added then removed.']. each = #rename ifTrue: [strm nextPutAll: 'Class name was changed.'; cr]. each = #add ifTrue: [strm nextPutAll: 'Class definition was added.'; cr]. each = #change ifTrue: [strm nextPutAll: 'Class definition was changed.'; cr]. each = #reorganize ifTrue: [strm nextPutAll: 'Class organization was changed.'; cr]. each = #comment ifTrue: [strm nextPutAll: 'New class comment.'; cr. ]]. ^ contents := strm contents].! Item was changed: + (PackageInfo named: 'Tools') postscript: 'ChangeSorter allSubInstancesDo: [:sorter | + (sorter instVarNamed: ''contentsAreStyleable'') ifNil: [ + sorter instVarNamed: ''contentsAreStyleable'' put: true]].'! - (PackageInfo named: 'Tools') postscript: '(Smalltalk globals at: #ObjectsUnderInspection ifAbsent: [#()]) - do: [:objectUnderInspection | - ToolSet inspect: objectUnderInspection]. - Smalltalk globals removeKey: #ObjectsUnderInspection.'! From commits at source.squeak.org Wed Mar 10 17:51:37 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 10 Mar 2021 17:51:37 0000 Subject: [squeak-dev] The Inbox: Tools-ct.1032.mcz Message-ID: A new version of Tools was added to project The Inbox: http://source.squeak.org/inbox/Tools-ct.1032.mcz ==================== Summary ==================== Name: Tools-ct.1032 Author: ct Time: 10 March 2021, 6:51:33.356304 pm UUID: 897e4ea2-3740-6a45-a054-d7da65105568 Ancestors: Tools-mt.1030 In the Message Names tool, show definition, comment, and hierarchy for class hits. In particular helpful to find out efficiently whether a selector belongs to a binding or to an actual class. =============== Diff against Tools-mt.1030 =============== Item was changed: ----- Method: MessageNames>>computeMessageList (in category 'search') ----- computeMessageList + | selector | + selectorListIndex = 0 ifTrue: [^ #()]. + + selector := selectorList at: selectorListIndex. + ^ (selector first isUppercase ifTrue: [Smalltalk classNamed: selector]) + ifNotNil: [:class | + class := Smalltalk classNamed: selector. + #(Definition Comment Hierarchy) collect: [:sel | + MethodReference class: class selector: sel] ] + ifNil: [self systemNavigation allImplementorsOf: selector]! - ^ selectorListIndex = 0 - ifTrue: [#()] - ifFalse: [self systemNavigation - allImplementorsOf: (selectorList at: selectorListIndex)]! Item was changed: ----- Method: MessageNames>>selectedMessageName (in category 'message list') ----- selectedMessageName selectorList basicSize = 0 ifTrue: [^ nil]. "Deals with selectorList nil or empty" + ^super selectedMessageName ifNil: [ + "only message name selected" + selectorList at: (selectorListIndex max: 1) ifAbsent: [nil] "If no selection we can still find a selector"]! - ^selectorList at: (selectorListIndex max: 1) ifAbsent: [nil] "If no selection we can still find a selector"! Item was changed: ----- Method: MessageSet>>aboutToStyle: (in category 'code pane') ----- + aboutToStyle: aStyler + "This is a notification that aStyler is about to re-style its text. + Set the classOrMetaClass in aStyler, so that identifiers will be resolved correctly. - aboutToStyle: aPluggableShoutMorphOrView - "This is a notification that aPluggableShoutMorphOrView is about to re-style its text. - Set the classOrMetaClass in aPluggableShoutMorphOrView, so that identifiers - will be resolved correctly. Answer true to allow styling to proceed, or false to veto the styling" | selectedMessageName showingMethod | self showingSource ifFalse: [^false]. selectedMessageName := self selectedMessageName. showingMethod := (#(Comment Definition Hierarchy) includes: selectedMessageName) not. + aStyler parseAMethod: showingMethod. "Hack!! setting classOrMetaClass: to nil allows doit or class definition colouring." + aStyler classOrMetaClass: (showingMethod ifTrue: [self selectedClassOrMetaClass]). - aPluggableShoutMorphOrView classOrMetaClass: (showingMethod ifTrue: [self selectedClassOrMetaClass]). ^(#(Comment Hierarchy) includes: selectedMessageName) not! Item was changed: ----- Method: MessageSet>>selectedMessage (in category 'message list') ----- selectedMessage "Answer the source method for the currently selected message." - self setClassAndSelectorIn: [:class :selector | | source | class ifNil: [^ 'Class vanished']. selector first isUppercase ifTrue: [selector == #Comment ifTrue: + ["currentCompiledMethod := class organization commentRemoteStr." - [currentCompiledMethod := class organization commentRemoteStr. ^ class comment]. selector == #Definition ifTrue: [^ class definition]. selector == #Hierarchy ifTrue: [^ class printHierarchy]]. source := class sourceMethodAt: selector ifAbsent: [currentCompiledMethod := nil. ^ 'Missing']. self showingDecompile ifTrue: [^ self decompiledSourceIntoContents]. currentCompiledMethod := class compiledMethodAt: selector ifAbsent: [nil]. self showingDocumentation ifTrue: [^ self commentContents]. source := self sourceStringPrettifiedAndDiffed. ^ source asText makeSelectorBoldIn: class]! From commits at source.squeak.org Wed Mar 10 17:55:04 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 10 Mar 2021 17:55:04 0000 Subject: [squeak-dev] The Inbox: Monticello-ct.739.mcz Message-ID: A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.739.mcz ==================== Summary ==================== Name: Monticello-ct.739 Author: ct Time: 10 March 2021, 6:55:01.889559 pm UUID: aec2f89c-cf99-ea47-91f4-4cdf2ebd5bb9 Ancestors: Monticello-mt.736 Tweaks 'add to current change set' command to create a changeset from all (non-ignored) items in an operations browser. Also hides the 'browse full' command from the menu if not any item is selected since it does not have any function in this case. =============== Diff against Monticello-mt.736 =============== Item was changed: ----- Method: MCCodeTool>>methodListMenu: (in category 'menus') ----- methodListMenu: aMenu "Build the menu for the selected method, if any." self selectedMessageName ifNil: [items notEmpty ifTrue: [aMenu addList:#( - ('browse full (b)' browseMethodFull) ('fileOut (o)' fileOutMessage))]] ifNotNil: [ aMenu addList:#( ('browse full (b)' browseMethodFull) ('browse hierarchy (h)' browseClassHierarchy) ('browse protocol (p)' browseFullProtocol) - ('fileOut (o)' fileOutMessage) ('printOut' printOutMessage) ('copy selector (c)' copySelector) ('copy reference (C)' copyReference)). aMenu addList: #( - ('browse senders (n)' browseSendersOfMessages) ('browse implementors (m)' browseMessages) ('inheritance (i)' methodHierarchy) ('versions (v)' browseVersions) ('change sets with this method' findMethodInChangeSets) " ('x revert to previous version' revertToPreviousVersion)" ('remove from current change set' removeFromCurrentChanges) " ('x revert & remove from changes' revertAndForget)" ('add to current change set' adoptMessageInCurrentChangeset) " ('x copy up or copy down...' copyUpOrCopyDown)" " ('x remove method (x)' removeMessage)" "-" ). ]. " aMenu addList: #( ('x inst var refs...' browseInstVarRefs) ('x inst var defs...' browseInstVarDefs) ('x class var refs...' browseClassVarRefs) ('x class variables' browseClassVariables) ('x class refs (N)' browseClassRefs) ). " ^ aMenu ! Item was added: + ----- Method: MCOperationsBrowser>>adoptMessageInCurrentChangeset (in category 'menus') ----- + adoptMessageInCurrentChangeset + + selection ifNotNil: [^ super adoptMessageInCurrentChangeset]. + + items do: [:item | + self forItem: item setClassAndSelectorIn: [:class :selector | + ChangeSet current adoptSelector: selector forClass: class]]. + self changed: #annotations.! Item was added: + ----- Method: MCOperationsBrowser>>forItem:setClassAndSelectorIn: (in category 'private') ----- + forItem: item setClassAndSelectorIn: classSelectorBlock + + item definition isMethodDefinition ifFalse: [self halt]. + ^ classSelectorBlock + value: item definition actualClass + value: item definition selector! Item was changed: ----- Method: MCOperationsBrowser>>methodListMenu: (in category 'menus') ----- methodListMenu: aMenu + selection + ifNil: [items ifNotEmpty: [ + aMenu addList: #( + ('add to current change set' adoptMessageInCurrentChangeset))]] + ifNotNil: [aMenu addList: #( - selection ifNotNil: - [aMenu addList: #( ('install' installSelection) ('revert (x)' revertSelection) ('browse origin' browseSelectionOrigin) -)]. self unchangedMethods ifNotEmpty: [aMenu addList: #( ('revert unchanged methods...' revertUnchangedMethods) ('filter out unchanged methods...' filterOutUnchangedMethods) -)]. super methodListMenu: aMenu. ^ aMenu! Item was added: + ----- Method: MCSaveVersionDialog>>adoptMessageInCurrentChangeset (in category 'menus') ----- + adoptMessageInCurrentChangeset + + selection ifNotNil: [^ super adoptMessageInCurrentChangeset]. + + (items copyWithoutAll: ignore) do: [:item | + self forItem: item setClassAndSelectorIn: [:class :selector | + ChangeSet current adoptSelector: selector forClass: class]]. + self changed: #annotations.! From lewis at mail.msen.com Thu Mar 11 00:56:51 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Wed, 10 Mar 2021 19:56:51 -0500 Subject: [squeak-dev] About a new "Math" package ... (was: Proposal: Geometry Classes) In-Reply-To: References: <1a9be046bbd44194a8a755a773d5daa0@student.hpi.uni-potsdam.de> <94e66631f6e64ad184b54d3ee3d86232@student.hpi.uni-potsdam.de> Message-ID: <20210311005651.GA87747@shell.msen.com> The category "Kernel-Numbers" already makes good sense to me. Mathematics uses numbers, but numbers themselves are not mathematics. And objects that represent magnitude are an essential part of any minimal core/kernel. Regarding terminology, if I were to put the various representations of numeric magnitude into a package called "Math", then I would call it "Math-Magnitude" rather than "Math-Quantity". The reason for this is that the term "Quantity" implies discreet counts (e.g. whole numbers), whereas "Magnitude" implies real numbers. For example, the number of seconds in one minute is a quantity, but the duration of one minute measured in units of seconds is a magnitude. I do like the idea of moving mathematical concepts that use numbers into a separate package. Caveat, I am not a mathematician. Dave On Wed, Mar 10, 2021 at 11:22:03AM +0100, Nicolas Cellier wrote: > Hi Marcel, > I see the POV of classification for understanding and teaching. But isn't > there also the perspective of re-constructing a system from minimal > core/kernel ? > Also, is SmallInteger really related to Math? I do not see it as a > specialization, but rather as providing some kernel operations (primitives) > onto which we can build/generalize Integer math. > > Le mer. 10 mars 2021 ?? 09:48, Marcel Taeumel a > ??crit : > > > Hi Nicolas, > > > > in the long term, we might want to re-design the entire "Kernel" > > perspective to be specialized attachments to other packages. I would like > > to see a clear separation of non-programming, high-level concepts and > > technical, low-level optimizations. > > > > For example, "Integer" could be discoverable through "Math-Quantity" while > > "SmallInteger" could reside in "MathExtras-Kernel" or similar. Eventually, > > we would turn around the perspective from primarily technical to primarily > > conceptual. Note that the inheritance tree would still look the same. > > > > Another example would consider RawBitsArray. "Rectangle" could reside in > > "Math-Geometry" while "Float32Rectangle" could be a subclass of > > "Float32Array" and hence reside in "MathExtras-Collections" or similar, > > optimized for FFI. > > > > A similar example can be constructed for "Quanternion" and > > "Float32Quaternion". > > > > Best, > > Marcel > > > > Am 09.03.2021 18:49:55 schrieb Nicolas Cellier < > > nicolas.cellier.aka.nice at gmail.com>: > > Wow, high level of brainstorming, not sure I can catch up ;) > > > > I'm not sure whether Number subclasses should be put in Math, they are > > so essential to the Kernel... > > > > What could obviously go in some extra Math-something is for example > > all the function extensions (inverse trigonometry, hyperbolic, ...) > > For trigonometry, not sure, it's essential to geometry. > > Also the accelerated large integer arithmetic would find its place in > > some extra package (not required in Kernel). > > No problem if you want Quaternion in trunk, if it can be useful for 3D > > geometry, then good. > > > > For RawBitArray, I'm not sure, it's more specific to programming than > > math per se (the fact that we use bounded integers of some > > byte-size...). RawBitsArray really shine when interacting with the > > outside world (importing large data sets from some standard format > > and/or passing them to FFI). > > > > Le mar. 9 mars 2021 ?? 14:28, Marcel Taeumel a ??crit : > > > > > > > non-ultimate partition > > > > > > The system evolves. Code changes. New insights will influence onward > > refactorings. That's always the baseline. ;-) > > > > > > Best, > > > Marcel > > > > > > Am 09.03.2021 14:27:06 schrieb Thiede, Christoph : > > > > > > From the perspective of "good old baby steps" and with the notion of > > "Extras" as a non-ultimate partition in mind, this sounds very reasonable > > ... :-) > > > > > > > > > Best, > > > > > > Christoph > > > > > > ________________________________ > > > Von: Squeak-dev im Auftrag von Taeumel, Marcel > > > Gesendet: Dienstag, 9. M??rz 2021 14:22:47 > > > An: squeak-dev > > > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: > > Geometry Classes) > > > > > > First step would be to assess whether something is "core or not". And > > "SomethingExtras" or "SomethingExtension" is a familiar pattern for this. > > Once a "MathExtras" package severely lacks cohesion, we can split it up > > again. > > > > > > Best, > > > Marcel > > > > > > Am 09.03.2021 14:18:39 schrieb Thiede, Christoph : > > > > > > Yeah, I see this point, but still ... "Extras" sounds kind of arbitrary > > to me. If you cannot find a precise name for a package, how high can its > > coherency be? :-) > > > > > > > > > Best, > > > Christoph > > > ________________________________ > > > Von: Squeak-dev im Auftrag von Taeumel, Marcel > > > Gesendet: Dienstag, 9. M??rz 2021 14:05:58 > > > An: squeak-dev > > > Betreff: Re: [squeak-dev] About a new "Math" package ... (was: Proposal: > > Geometry Classes) > > > > > > MathExtras might host low-level optimizations, as I exemplified: > > > > > > > And I would like to add that "number crunching" part around fancy > > graphics (e.g. OpenGL through FFI) to "Math-Collections" or maybe > > "MathExtras-Collections", looking at all the subclasses of RawBitsArray. > > > > > > :-) I assume that it may be beneficial to at least decide whether > > something is "core" or "extra". I would like to have this for "Math" from > > the beginning. > > > > > > Best, > > > Marcel > > > > > > Am 09.03.2021 13:10:39 schrieb Thiede, Christoph : > > > > > > Referring to the MathExtras proposal ... What is your general idea of an > > extra package? I know Morphic-Extras as a collection of non-necessary > > tools, helpers, and demos, but the general idea sounds kind of vague to me. > > > > > > > > > CollectionsExtras would be a place for Text enhancements such as > > attributes (so actually, we could also call it simply "TextSupport" or > > something like this), MathExtras would contain "math stuff that is not > > necessary" ... > > > > > > Do you have any more precise idea of what classifies an extra package or > > would "MathSmorgasbord" be a franker name for the package? If yes, this > > would make me think about the coherency of such a package ... Just my 2 > > cents, of course. :) > > > > > > > > > Best, > > > > > > Christoph > > > > > > ________________________________ > > > Von: Thiede, Christoph > > > Gesendet: Dienstag, 9. M??rz 2021 12:56:04 > > > An: squeak-dev > > > Betreff: AW: [squeak-dev] About a new "Math" package ... (was: Proposal: > > Geometry Classes) > > > > > > > > > Hi Marcel, > > > > > > > > > sounds interesting! I have a few thoughts regarding package dependencies. > > > > > > > > > As far as I understand, the dependency structure would look kind like > > this: > > > > > > > > > Kernel-Objects -> Math-Quantity (see senders of SmallInteger for > > example), Math-Analysis (see senders of #asFloat for example) > > > > > > Math-Quantity -> Kernel (superclass), Math-Analysis (see senders of > > #asFloat) > > > > > > Math-Analysis -> Kernel (superclass), Math-Quantity (maybe?) > > > > > > Math-Geometry -> Kernel (of course), Math-Quantity (senders of > > SmallInteger), Math-Analysis (see senders of #asFloat) > > > > > > Math-Collections would probably depend on all other packages? > > > > > > > > > The question is which of these dependencies can be eliminated and which > > are a problem at all. > > > > > > > > > What about Random? Do you want to keep it in Kernel, depending on Math? > > > > > > > > > What is about dependencies from Number (Kernel-Objects) to Float > > (Math-Analysis), for example, #asFloat, but also sophisticated things such > > as #sin? Do we want to create a bunch of extension methods for this? > > > > > > In any case, I think the "math functions" protocol on Collection should > > become an extension protocol ("*Math-Analysis" or > > "*Math-Analysis-enumerating"). > > > > > > > > > Best, > > > Christoph > > > ________________________________ > > > Von: Squeak-dev im Auftrag von Taeumel, Marcel > > > Gesendet: Dienstag, 9. M??rz 2021 10:50:09 > > > An: squeak-dev > > > Betreff: [squeak-dev] About a new "Math" package ... (was: Proposal: > > Geometry Classes) > > > > > > Hi all! > > > > > > I think that we would rather need a "Math" package with "Math-Geometry" > > being one of multiple categories. > > > > > > Please take a look at the following proposed classification: > > > > > > Kernel-Objects (= not Kernel-Numbers) > > > Magnitude > > > Number > > > > > > Math-Quantity > > > Integer (+ subclasses) > > > Fraction > > > ScaledDecimal > > > > > > Math-Analysis > > > Complex > > > Float (+ subclasses) > > > Quaternion > > > > > > Math-Geometry > > > Point > > > Line > > > Rectangle > > > Polygon > > > Path > > > > > > Math-Collections > > > Vector2 (from 3DTransform, CroquetGL, etc.) > > > Vector3 > > > Vector4 > > > Matrix2x3 > > > Matrix4x4 > > > VectorArray > > > ... > > > > > > It would involve some effort, especially to untangle "ST80-Paths" from > > graphics :-) Eventually, I would like to see Nicolas' efforts for "Complex" > > and "Quaternion" in Trunk. And I would like to add that "number crunching" > > part around fancy graphics (e.g. OpenGL through FFI) to "Math-Collections" > > or maybe "MathExtras-Collections", looking at all the subclasses of > > RawBitsArray. > > > > > > May I add "Math" and "MathExtras" packages so that we can slowly get > > started? :-) > > > > > > Best, > > > Marcel > > > > > > Am 22.01.2019 18:32:10 schrieb patrick.rein at hpi.uni-potsdam.de : > > > > > > Hi everyone, > > > > > > during some recent clean-up an issue with geometry objects came up. As a > > result the following idea came up which I thereby would like to put out for > > an initial discussion. > > > > > > In case we find that this might be useful, I would continue by > > implementing a first prototype of the package as a foundation of a more > > in-depth discussion later on. > > > > > > Bests > > > Patrick > > > > > > # Squeak Change Proposal - Geometry Package > > > > > > ## Why? > > > Squeak implements basic geometry logic in too many different places. For > > example intersection of different kinds of geometric objects is implemented > > all over Morphic, ST80, Balloon, Graphics, and Etoys. Such extensive > > scattering across packages and classes impedes modularity, that is, > > readability and extensibility. An example for this recently came up when we > > discovered an issue with testing for graphical intersections between > > PolygonMorph and RectangleMorph. It was not possible to compute that > > overlapping area because the class Rectangle omits to provide an important > > method. A quick fix would entail unnecessary dependencies (here: Morphic -> > > Balloon) or duplicated code (see also > > http://bugs.squeak.org/view.php?id=7872). Consequently, we might want to > > modularize the geometry objects and operations. As a side effect, dependent > > packages such as Morphic can be simplified a little bit (more). > > > > > > ## Scope > > > The proposed package should cover basic 2D geometric objects and their > > operations represented by the following classes: > > > - Point > > > - Line > > > - LineSegment > > > - Polygon > > > - Rectangle (as an optimization as it could be represented as a special > > Polygon already) > > > > > > Most classes could simply be moved from their previous packages. > > Afterwards the interfaces would need to be made consistent with each other > > to allow interoperability of all geometry classes within the new package. > > > > > > ### Affected classes: > > > - All classes in ST80-Paths > > > - LineSegement, Bezier2Segment, Bezier3Segment (Balloon-Geometry) > > > - Rectangle, Quadrangle, Point (Graphics-Primitives) > > > - LineIntersections, LineIntersectionSegment, LineIntersectionEvent > > (Etoys-Squeakland-Graphics-Tools-Intersection) > > > > > > ## Open questions > > > - Should this become a single new package or a subcategory in the > > Graphics package? > > > - Should the package contain an Ellipses class? > > > - Should we model curved line segments as BezierLineSegments, > > CurvedLineSegment, or Arc? > > > > > > ## Risks > > > - This would potentially deprecate the existing ST80 geometry classes > > (ST80-Paths) > > > - Some of the new classes will cause name clashes with existing classes. > > For example Line is currently in ST-80 and represents a line segment, and > > the class LineSegment is a line segment but not in the geometric sense as > > it also incorporates arcs. Both names might then be used by new classes > > with different meanings. This might be mitigated by introducing a > > pre-/postfix for the names of the new classes. > > > > > > > > > > > > > From lewis at mail.msen.com Thu Mar 11 01:25:13 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Wed, 10 Mar 2021 20:25:13 -0500 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> Message-ID: <20210311012513.GA94119@shell.msen.com> On Tue, Mar 09, 2021 at 01:47:49PM +0000, Thiede, Christoph wrote: > > "I want a two second delay" is perfectly valid :D > > Maybe a native English speaker can correct me but afaik, in the grammar > dependency tree of "two-second delay", "two-second" is not an independet > noun but a pre-modifying phrase only. Shall we really start to support > even more different types of words in an object-oriented language like > Smalltalk? Imho, substantives and verbs are already enough. :-) > I am a native Engish speaker with a poor understanding of grammar, so that makes me a good person to attempt an answer ;-) The use of singular "second" or plural "seconds" may depend on the context of the expression, but in any case if I were to hear someone say "five second" I would understand it to refer to five seconds, not one second. If I were to try to enforce correct English (is there such a thing? of course not), then I might try to treat "five second" as an error. But we do not really need to enforce English syntax rules, and in this case it is more important for the expression to do the right thing. So for me as an English speaker, I overlook the difference between "second" and "seconds" and I prefer to have the expression do what I expect in either case. For this reason, it makes sense to me for #second and #seconds to be treated as synonyms. Dave From nicolas.cellier.aka.nice at gmail.com Thu Mar 11 07:16:51 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Thu, 11 Mar 2021 08:16:51 +0100 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <20210311012513.GA94119@shell.msen.com> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> <20210311012513.GA94119@shell.msen.com> Message-ID: Grammar rules apart, if second has to answer a unit of 1 second, why the hell send such message to 5? Why not Time second for example? Le jeu. 11 mars 2021 à 02:25, David T. Lewis a écrit : > On Tue, Mar 09, 2021 at 01:47:49PM +0000, Thiede, Christoph wrote: > > > "I want a two second delay" is perfectly valid :D > > > > Maybe a native English speaker can correct me but afaik, in the grammar > > dependency tree of "two-second delay", "two-second" is not an independet > > noun but a pre-modifying phrase only. Shall we really start to support > > even more different types of words in an object-oriented language like > > Smalltalk? Imho, substantives and verbs are already enough. :-) > > > > I am a native Engish speaker with a poor understanding of grammar, so > that makes me a good person to attempt an answer ;-) > > The use of singular "second" or plural "seconds" may depend on the > context of the expression, but in any case if I were to hear someone > say "five second" I would understand it to refer to five seconds, not > one second. If I were to try to enforce correct English (is there such > a thing? of course not), then I might try to treat "five second" as > an error. But we do not really need to enforce English syntax rules, > and in this case it is more important for the expression to do the > right thing. > > So for me as an English speaker, I overlook the difference between > "second" and "seconds" and I prefer to have the expression do what > I expect in either case. > > For this reason, it makes sense to me for #second and #seconds to > be treated as synonyms. > > Dave > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Thu Mar 11 07:33:38 2021 From: m at jaromir.net (Jaromir Matas) Date: Thu, 11 Mar 2021 01:33:38 -0600 (CST) Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: References: <1615235931986-0.post@n4.nabble.com> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> Message-ID: <1615448018993-0.post@n4.nabble.com> To add my 2¢; how about, in the spirit of the pidgin English tradition: aCollection collect: [:x | x squared] selecting: #even stopIf: [:x | x squared = 2500] complemented by: aCollection collect: [:x | x squared] selecting: #even stopBefore: #isNil ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Thu Mar 11 07:58:43 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 11 Mar 2021 08:58:43 +0100 Subject: [squeak-dev] The Inbox: Monticello-ct.737.mcz In-Reply-To: References: Message-ID: -1 #save does not inform the user about the actual problem between Inbox and Trunk/Treated anymore. Good error messages are paramount for usability. To make this a constructive discussion: This looks like "premature abstraction". What are other examples for source/sink repositories? Best, Marcel Am 09.03.2021 14:00:07 schrieb commits at source.squeak.org : A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.737.mcz ==================== Summary ==================== Name: Monticello-ct.737 Author: ct Time: 9 March 2021, 1:59:56.826559 pm UUID: 697dc3bc-f4f7-3e43-b05d-d6a1f5fb421e Ancestors: Monticello-mt.736 Revises warnings shown before saving a version. In #checkForNewVersions, do not only check the current repository (e.g. inbox) but also the sink repository (e.g. trunk). Also generalizes the idea of sink repositories and resolve hard-coded repositores in Monticello-UI. =============== Diff against Monticello-mt.736 =============== Item was added: + ----- Method: MCRepository>>allSinkRepositories (in category 'accessing') ----- + allSinkRepositories + "If the workflow of the receiver requires to move new versions into one of any other repositories in the end, answer all these available sink repositories here." + + self = MCRepository inbox ifTrue: [ + ^ {MCRepository trunk. MCRepository treated}]. + + ^ Array empty! Item was added: + ----- Method: MCRepository>>defaultSinkRepository (in category 'accessing') ----- + defaultSinkRepository + "If the workflow of the receiver requires to move new versions into another repository in the end, answer this default sink repository here." + + self = MCRepository inbox ifTrue: [ + ^ MCRepository trunk]. + + ^ nil! Item was changed: ----- Method: MCRepositoryInspector>>save (in category 'actions') ----- save + + | targetRepository | + targetRepository := self pickRepository ifNil: [^ self]. + + (self repository allSinkRepositories includes: targetRepository) ifTrue: [ + self notify: (String streamContents: [:stream | + stream nextPutAll: 'Versions from this repository should only be moved, not copied.' translated. + (self repository isKindOf: MCHttpRepository) ifTrue: [ + stream space; nextPutAll: ('Instead, use the web interface via {1} to manage contributions.' translated format: {(Url absoluteFromText: self repository description) + path: ''; + downloadUrl})]. + stream cr; cr; nextPutAll: 'Do you want to proceed anyway?' withCRs translated])]. + + repository storeVersion: self version.! - self pickRepository ifNotNil: - [:repository | - (self repository = MCRepository inbox and: - [repository = MCRepository trunk or: [repository = MCRepository treated]]) ifTrue: - [self notify: 'Versions from the inbox should only be moved, not copied. Instead, use the web interface via source.squeak.org to manage inbox contributions.\\Do you want to proceed anyway?' translated withCRs]. - repository storeVersion: self version]! Item was changed: ----- Method: MCWorkingCopyBrowser>>checkForNewerVersions (in category 'actions') ----- checkForNewerVersions + | newer | newer := workingCopy possiblyNewerVersionsIn: self repository. + (newer notEmpty ==> [ + self confirm: ('{1}\\{2}\\{3}' withCRs translated format: { + 'CAUTION!! These versions in the repository may be newer:' translated. + (newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149. + 'Do you really want to save this version?' translated}) ]) + ifFalse: [^ false]. + + self repository defaultSinkRepository ifNotNil: [:sinkRepository | + newer := workingCopy possiblyNewerVersionsIn: sinkRepository. + (newer notEmpty ==> [ + self confirm: ('{1}\\{2}\\{3}' withCRs translated format: { + 'CAUTION!! These versions in the sink repository\({1})\may be newer:' withCRs translated format: {sinkRepository description}. + (newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149. + 'Do you really want to save this version?' translated}) ]) + ifFalse: [^ false]]. + + ^ true! - ^ newer isEmpty or: [ - self confirm: 'CAUTION!! These versions in the repository may be newer:', - String cr, ((newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149), String cr, - 'Do you really want to save this version?'].! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Thu Mar 11 08:04:08 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 11 Mar 2021 09:04:08 +0100 Subject: [squeak-dev] The Inbox: Tools-ct.1015.mcz In-Reply-To: References: Message-ID: Hi there :-) -0.5 for the output beautification +1 for the rest If you would like to add commas to the text, please also put one before the "and": https://www.grammarly.com/blog/what-is-the-oxford-comma-and-why-do-people-care-so-much-about-it/ [https://www.grammarly.com/blog/what-is-the-oxford-comma-and-why-do-people-care-so-much-about-it/] In general, I don't think that adding more characters to the annotation bar is a good idea since its space is restricted so much already. Also, maybe a simpler representation would promote do-it scripting? :-) Such as through #splitBy:, which becomes more complicated with "," and "and". Best, Marcel Am 01.11.2020 14:58:58 schrieb commits at source.squeak.org : Christoph Thiede uploaded a new version of Tools to project The Inbox: http://source.squeak.org/inbox/Tools-ct.1015.mcz ==================== Summary ==================== Name: Tools-ct.1015 Author: ct Time: 1 November 2020, 3:58:41.62325 pm UUID: 0f1723d1-90c5-ca4e-88ad-56f6800b2b17 Ancestors: Tools-tpr.1014 Beautify CodeHolder >> #annotationForSelector:ofClass: implementation and output. Remove dangling separator character and add multilingual support. Example - before: mt 2/13/2020 13:49 · running · 2 implementors · in change sets: Morphic-pre.1466 Morphic-mt.1507 Morphic-mt.1607 Morphic-cmm.1617 Morphic-mt.1622 · Example - after: mt 2/13/2020 13:49 · running · 2 implementors · in change sets: Morphic-pre.1466, Morphic-mt.1507, Morphic-mt.1607, Morphic-cmm.1617 and Morphic-mt.1622 =============== Diff against Tools-tpr.1014 =============== Item was changed: ----- Method: CodeHolder>>annotationForSelector:ofClass: (in category 'annotation') ----- annotationForSelector: aSelector ofClass: aClass "Provide a line of content for an annotation pane, representing information about the given selector and class" | separator aStream requestList | aSelector == #Comment ifTrue: [^ self annotationForClassCommentFor: aClass]. aSelector == #Definition ifTrue: [^ self annotationForClassDefinitionFor: aClass]. aSelector == #Hierarchy ifTrue: [^ self annotationForHierarchyFor: aClass]. aStream := (String new: 512) writeStream. requestList := self annotationRequests. + separator := self annotationSeparator. - separator := requestList size > 1 - ifTrue: [self annotationSeparator] - ifFalse: ['']. requestList do: [:aRequest | | aString sendersCount aComment aCategory implementorsCount aList stamp authorInitials | aRequest == #firstComment ifTrue: [aComment := aClass firstCommentAt: aSelector. aComment isEmptyOrNil + ifFalse: [aStream nextPutAll: aComment]]. - ifFalse: [aStream nextPutAll: aComment , separator]]. aRequest == #masterComment ifTrue: [aComment := aClass supermostPrecodeCommentFor: aSelector. aComment isEmptyOrNil + ifFalse: [aStream nextPutAll: aComment]]. - ifFalse: [aStream nextPutAll: aComment , separator]]. aRequest == #documentation ifTrue: [aComment := aClass precodeCommentOrInheritedCommentFor: aSelector. aComment isEmptyOrNil + ifFalse: [aStream nextPutAll: aComment]]. - ifFalse: [aStream nextPutAll: aComment , separator]]. aRequest == #timeStamp ifTrue: [stamp := self timeStamp. aStream + nextPutAll: (stamp ifEmpty: ['no timeStamp' translated])]. - nextPutAll: (stamp size > 0 - ifTrue: [stamp , separator] - ifFalse: ['no timeStamp' , separator])]. aRequest == #author ifTrue: [authorInitials := self timeStamp findTokens ifEmpty: [''] ifNotEmpty: [:tokens | tokens first]. aStream nextPutAll: (SystemNavigation authorsInverted at: authorInitials ifPresent: [:fullNames | fullNames anyOne] ifAbsent: ['unknown author']), separator]. aRequest == #messageCategory ifTrue: [aCategory := aClass organization categoryOfElement: aSelector. aCategory ifNotNil: ["woud be nil for a method no longer present, e.g. in a recent-submissions browser" + aStream nextPutAll: aCategory]]. - aStream nextPutAll: aCategory , separator]]. aRequest == #sendersCount ifTrue: [sendersCount := (self systemNavigation allCallsOn: aSelector) size. sendersCount := sendersCount = 1 + ifTrue: ['1 sender' translated] + ifFalse: ['{1} senders' translated format: {sendersCount}]. + aStream nextPutAll: sendersCount]. - ifTrue: ['1 sender'] - ifFalse: [sendersCount printString , ' senders']. - aStream nextPutAll: sendersCount , separator]. aRequest == #implementorsCount ifTrue: [implementorsCount := self systemNavigation numberOfImplementorsOf: aSelector. implementorsCount := implementorsCount = 1 + ifTrue: ['1 implementor' translated] + ifFalse: ['{1} implementors' translated format: {implementorsCount}]. + aStream nextPutAll: implementorsCount]. - ifTrue: ['1 implementor'] - ifFalse: [implementorsCount printString , ' implementors']. - aStream nextPutAll: implementorsCount , separator]. aRequest == #priorVersionsCount ifTrue: [self addPriorVersionsCountForSelector: aSelector ofClass: aClass to: aStream]. aRequest == #priorTimeStamp ifTrue: [stamp := VersionsBrowser timeStampFor: aSelector class: aClass reverseOrdinal: 2. stamp + ifNotNil: [aStream nextPutAll: 'prior time stamp: ' translated , stamp]]. - ifNotNil: [aStream nextPutAll: 'prior time stamp: ' , stamp , separator]]. aRequest == #recentChangeSet ifTrue: [aString := ChangesOrganizer mostRecentChangeSetWithChangeForClass: aClass selector: aSelector. + aStream nextPutAll: aString]. - aString size > 0 - ifTrue: [aStream nextPutAll: aString , separator]]. aRequest == #allChangeSets ifTrue: [aList := ChangesOrganizer allChangeSetsWithClass: aClass selector: aSelector. + aList + ifNotEmpty: [aList size = 1 + ifTrue: [aStream nextPutAll: 'only in change set ' translated] + ifFalse: [aStream nextPutAll: 'in change sets: ' translated]. + aStream nextPutAll: (aList collect: + [:changeSet | changeSet name]) asCommaStringAnd] + ifEmpty: [aStream nextPutAll: 'in no change set' translated]]] + separatedBy: [ + aStream nextPutAll: separator]. - aList size > 0 - ifTrue: [aList size = 1 - ifTrue: [aStream nextPutAll: 'only in change set '] - ifFalse: [aStream nextPutAll: 'in change sets: ']. - aList - do: [:aChangeSet | aStream nextPutAll: aChangeSet name , ' ']] - ifFalse: [aStream nextPutAll: 'in no change set']. - aStream nextPutAll: separator]]. ^ aStream contents! -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Thu Mar 11 09:39:13 2021 From: m at jaromir.net (Jaromir Matas) Date: Thu, 11 Mar 2021 03:39:13 -0600 (CST) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615372211711-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615372211711-0.post@n4.nabble.com> Message-ID: <1615455553312-0.post@n4.nabble.com> Hi Christoph, hi all, There's a couple of (probably) independent issues: 1. broken #isTerminated - fix suggested in the previous post, will send to The Inbox 2. Debugger leaving unterminated processes behind (see in Process Browser). The problem is in my view in Debugger >> windowIsClosing: Debugger >> windowIsClosing "My window is being closed; clean up. Restart the low space watcher." interruptedProcess == nil ifTrue: [^ self]. interruptedProcess terminate. >>> at this point the interruptedProcess may still not be terminated, so I suggest to replace the above line by: >>> [interruptedProcess isTerminated] whileFalse: [interruptedProcess terminate]. interruptedProcess := nil. contextStack := nil. receiverInspector := nil. contextVariablesInspector := nil. Smalltalk installLowSpaceWatcher. "restart low space handler" This patch would cleanup unterminated processes when closing the debugger and resolve my examples without non-local returns but your example with non-local return would still remain unresolved. Note: I know nothing about the Debugger so take my patch as a desperate attempt :) 3. your fix `ctxt restart` applied for this recursive scenario: x:=nil. [self error: 'x1'] ensure: [ [self error: 'x2'] ensure: [ [self error: 'x3'] ensure: [x:=3]. x:=2]. x:=1]. ... leads me to a question what the expected beahvior actually is: If you Abandon the FIRST error debugger - do you expect to continue to the second debugger, abandon it and continue to the third debugger or rather quit right after the FIRST debugger Abandon? If the former then what would the difference between Proceed and Abandon be? I'm no longer sure of anything :) Your fix leads to the former. Please let me know what you think. Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 09:48:05 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 09:48:05 +0000 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <1615448018993-0.post@n4.nabble.com> References: <1615235931986-0.post@n4.nabble.com> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> , <1615448018993-0.post@n4.nabble.com> Message-ID: <0475444a09b2428ab84955c7f70c292a@student.hpi.uni-potsdam.de> -1 :-) For the same reason why I argued against #do:upThrough: - the order of arguments would be confusing. We would first check to stop, and then do any collect/select operations. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Donnerstag, 11. März 2021 08:33:38 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... To add my 2¢; how about, in the spirit of the pidgin English tradition: aCollection collect: [:x | x squared] selecting: #even stopIf: [:x | x squared = 2500] complemented by: aCollection collect: [:x | x squared] selecting: #even stopBefore: #isNil ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 09:56:11 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 09:56:11 +0000 Subject: [squeak-dev] The Inbox: Tools-ct.1015.mcz In-Reply-To: References: , Message-ID: Hi Marcel, thanks for the feedback! I'm currently continuing the refactoring of this method anyway, so this version can be moved to the treated inbox of course. Yes, I think #asCommaStringAnd should be fixed (even though the oxford comma appears not to be the universal truth because, in certain scenarios, it can also add ambiguity - see https://en.wikipedia.org/wiki/Serial_comma#Creating_ambiguity, but it is being widely accepted). Will upload a patch right now. :-) > In general, I don't think that adding more characters to the annotation bar is a good idea Fair points. Will return to the single comma-separation in the next upload. Please note that the "and" was not the only part of the output beautification. I also removed the trailing separator character. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Donnerstag, 11. März 2021 09:04:08 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Tools-ct.1015.mcz Hi there :-) -0.5 for the output beautification +1 for the rest If you would like to add commas to the text, please also put one before the "and": https://www.grammarly.com/blog/what-is-the-oxford-comma-and-why-do-people-care-so-much-about-it/ In general, I don't think that adding more characters to the annotation bar is a good idea since its space is restricted so much already. Also, maybe a simpler representation would promote do-it scripting? :-) Such as through #splitBy:, which becomes more complicated with "," and "and". Best, Marcel Am 01.11.2020 14:58:58 schrieb commits at source.squeak.org : Christoph Thiede uploaded a new version of Tools to project The Inbox: http://source.squeak.org/inbox/Tools-ct.1015.mcz ==================== Summary ==================== Name: Tools-ct.1015 Author: ct Time: 1 November 2020, 3:58:41.62325 pm UUID: 0f1723d1-90c5-ca4e-88ad-56f6800b2b17 Ancestors: Tools-tpr.1014 Beautify CodeHolder >> #annotationForSelector:ofClass: implementation and output. Remove dangling separator character and add multilingual support. Example - before: mt 2/13/2020 13:49 · running · 2 implementors · in change sets: Morphic-pre.1466 Morphic-mt.1507 Morphic-mt.1607 Morphic-cmm.1617 Morphic-mt.1622 · Example - after: mt 2/13/2020 13:49 · running · 2 implementors · in change sets: Morphic-pre.1466, Morphic-mt.1507, Morphic-mt.1607, Morphic-cmm.1617 and Morphic-mt.1622 =============== Diff against Tools-tpr.1014 =============== Item was changed: ----- Method: CodeHolder>>annotationForSelector:ofClass: (in category 'annotation') ----- annotationForSelector: aSelector ofClass: aClass "Provide a line of content for an annotation pane, representing information about the given selector and class" | separator aStream requestList | aSelector == #Comment ifTrue: [^ self annotationForClassCommentFor: aClass]. aSelector == #Definition ifTrue: [^ self annotationForClassDefinitionFor: aClass]. aSelector == #Hierarchy ifTrue: [^ self annotationForHierarchyFor: aClass]. aStream := (String new: 512) writeStream. requestList := self annotationRequests. + separator := self annotationSeparator. - separator := requestList size > 1 - ifTrue: [self annotationSeparator] - ifFalse: ['']. requestList do: [:aRequest | | aString sendersCount aComment aCategory implementorsCount aList stamp authorInitials | aRequest == #firstComment ifTrue: [aComment := aClass firstCommentAt: aSelector. aComment isEmptyOrNil + ifFalse: [aStream nextPutAll: aComment]]. - ifFalse: [aStream nextPutAll: aComment , separator]]. aRequest == #masterComment ifTrue: [aComment := aClass supermostPrecodeCommentFor: aSelector. aComment isEmptyOrNil + ifFalse: [aStream nextPutAll: aComment]]. - ifFalse: [aStream nextPutAll: aComment , separator]]. aRequest == #documentation ifTrue: [aComment := aClass precodeCommentOrInheritedCommentFor: aSelector. aComment isEmptyOrNil + ifFalse: [aStream nextPutAll: aComment]]. - ifFalse: [aStream nextPutAll: aComment , separator]]. aRequest == #timeStamp ifTrue: [stamp := self timeStamp. aStream + nextPutAll: (stamp ifEmpty: ['no timeStamp' translated])]. - nextPutAll: (stamp size > 0 - ifTrue: [stamp , separator] - ifFalse: ['no timeStamp' , separator])]. aRequest == #author ifTrue: [authorInitials := self timeStamp findTokens ifEmpty: [''] ifNotEmpty: [:tokens | tokens first]. aStream nextPutAll: (SystemNavigation authorsInverted at: authorInitials ifPresent: [:fullNames | fullNames anyOne] ifAbsent: ['unknown author']), separator]. aRequest == #messageCategory ifTrue: [aCategory := aClass organization categoryOfElement: aSelector. aCategory ifNotNil: ["woud be nil for a method no longer present, e.g. in a recent-submissions browser" + aStream nextPutAll: aCategory]]. - aStream nextPutAll: aCategory , separator]]. aRequest == #sendersCount ifTrue: [sendersCount := (self systemNavigation allCallsOn: aSelector) size. sendersCount := sendersCount = 1 + ifTrue: ['1 sender' translated] + ifFalse: ['{1} senders' translated format: {sendersCount}]. + aStream nextPutAll: sendersCount]. - ifTrue: ['1 sender'] - ifFalse: [sendersCount printString , ' senders']. - aStream nextPutAll: sendersCount , separator]. aRequest == #implementorsCount ifTrue: [implementorsCount := self systemNavigation numberOfImplementorsOf: aSelector. implementorsCount := implementorsCount = 1 + ifTrue: ['1 implementor' translated] + ifFalse: ['{1} implementors' translated format: {implementorsCount}]. + aStream nextPutAll: implementorsCount]. - ifTrue: ['1 implementor'] - ifFalse: [implementorsCount printString , ' implementors']. - aStream nextPutAll: implementorsCount , separator]. aRequest == #priorVersionsCount ifTrue: [self addPriorVersionsCountForSelector: aSelector ofClass: aClass to: aStream]. aRequest == #priorTimeStamp ifTrue: [stamp := VersionsBrowser timeStampFor: aSelector class: aClass reverseOrdinal: 2. stamp + ifNotNil: [aStream nextPutAll: 'prior time stamp: ' translated , stamp]]. - ifNotNil: [aStream nextPutAll: 'prior time stamp: ' , stamp , separator]]. aRequest == #recentChangeSet ifTrue: [aString := ChangesOrganizer mostRecentChangeSetWithChangeForClass: aClass selector: aSelector. + aStream nextPutAll: aString]. - aString size > 0 - ifTrue: [aStream nextPutAll: aString , separator]]. aRequest == #allChangeSets ifTrue: [aList := ChangesOrganizer allChangeSetsWithClass: aClass selector: aSelector. + aList + ifNotEmpty: [aList size = 1 + ifTrue: [aStream nextPutAll: 'only in change set ' translated] + ifFalse: [aStream nextPutAll: 'in change sets: ' translated]. + aStream nextPutAll: (aList collect: + [:changeSet | changeSet name]) asCommaStringAnd] + ifEmpty: [aStream nextPutAll: 'in no change set' translated]]] + separatedBy: [ + aStream nextPutAll: separator]. - aList size > 0 - ifTrue: [aList size = 1 - ifTrue: [aStream nextPutAll: 'only in change set '] - ifFalse: [aStream nextPutAll: 'in change sets: ']. - aList - do: [:aChangeSet | aStream nextPutAll: aChangeSet name , ' ']] - ifFalse: [aStream nextPutAll: 'in no change set']. - aStream nextPutAll: separator]]. ^ aStream contents! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 11 09:56:56 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 11 Mar 2021 09:56:56 0000 Subject: [squeak-dev] The Inbox: Collections-ct.930.mcz Message-ID: A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-ct.930.mcz ==================== Summary ==================== Name: Collections-ct.930 Author: ct Time: 11 March 2021, 10:56:52.528559 am UUID: 6b1a0ee3-8c2d-a547-9ee2-f029a32d07b7 Ancestors: Collections-nice.929 Uses oxford comma in #asCommaStringAnd. Full discussion is here: http://forum.world.st/The-Inbox-Tools-ct-1015-mcz-tp5124286p5127654.html =============== Diff against Collections-nice.929 =============== Item was changed: ----- Method: Collection>>asCommaStringAnd (in category 'printing - obsolete') ----- asCommaStringAnd "Return collection printed as 'a, b and c' " self flag: #deprecate. + ^String streamContents: [:s | self asStringOn: s delimiter: ', ' last: ', and '] - ^String streamContents: [:s | self asStringOn: s delimiter: ', ' last: ' and '] ! From christoph.thiede at student.hpi.uni-potsdam.de Thu Mar 11 09:58:03 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Thu, 11 Mar 2021 03:58:03 -0600 (CST) Subject: [squeak-dev] The Inbox: Collections-ct.930.mcz In-Reply-To: References: Message-ID: <1615456683072-0.post@n4.nabble.com> Huh, why is this marked as to be deprecated? I think we could at least keep it on SequenceableCollection - I use this useful selector quite often ... Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Thu Mar 11 09:58:59 2021 From: m at jaromir.net (Jaromir Matas) Date: Thu, 11 Mar 2021 03:58:59 -0600 (CST) Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <0475444a09b2428ab84955c7f70c292a@student.hpi.uni-potsdam.de> References: <1615235931986-0.post@n4.nabble.com> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> <1615448018993-0.post@n4.nabble.com> <0475444a09b2428ab84955c7f70c292a@student.hpi.uni-potsdam.de> Message-ID: <1615456739100-0.post@n4.nabble.com> I know what you mean Christoph but I personally prefer to see the main, substantial action first and the infrequent event/stop condition last. It's like: "Go this way and do that until your reach a stop sign" ;) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 10:08:18 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 10:08:18 +0000 Subject: [squeak-dev] The Inbox: Monticello-ct.737.mcz In-Reply-To: References: , Message-ID: <2973dc2cdafa42c684abc4ae44f297f4@student.hpi.uni-potsdam.de> Hi Marcel, I think I preserved the original message - I only removed the little word "inbox" for the sake of abstraction. Is this what you are referring to? > This looks like "premature abstraction". Hm ... Can't we call it a feature of the Monticello API instead? I just wanted to get rid of these "magic numbers" in the UI methods. Smalltalk idioms told me to extract them into explaining methods. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Donnerstag, 11. März 2021 08:58:43 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Monticello-ct.737.mcz -1 #save does not inform the user about the actual problem between Inbox and Trunk/Treated anymore. Good error messages are paramount for usability. To make this a constructive discussion: This looks like "premature abstraction". What are other examples for source/sink repositories? Best, Marcel Am 09.03.2021 14:00:07 schrieb commits at source.squeak.org : A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.737.mcz ==================== Summary ==================== Name: Monticello-ct.737 Author: ct Time: 9 March 2021, 1:59:56.826559 pm UUID: 697dc3bc-f4f7-3e43-b05d-d6a1f5fb421e Ancestors: Monticello-mt.736 Revises warnings shown before saving a version. In #checkForNewVersions, do not only check the current repository (e.g. inbox) but also the sink repository (e.g. trunk). Also generalizes the idea of sink repositories and resolve hard-coded repositores in Monticello-UI. =============== Diff against Monticello-mt.736 =============== Item was added: + ----- Method: MCRepository>>allSinkRepositories (in category 'accessing') ----- + allSinkRepositories + "If the workflow of the receiver requires to move new versions into one of any other repositories in the end, answer all these available sink repositories here." + + self = MCRepository inbox ifTrue: [ + ^ {MCRepository trunk. MCRepository treated}]. + + ^ Array empty! Item was added: + ----- Method: MCRepository>>defaultSinkRepository (in category 'accessing') ----- + defaultSinkRepository + "If the workflow of the receiver requires to move new versions into another repository in the end, answer this default sink repository here." + + self = MCRepository inbox ifTrue: [ + ^ MCRepository trunk]. + + ^ nil! Item was changed: ----- Method: MCRepositoryInspector>>save (in category 'actions') ----- save + + | targetRepository | + targetRepository := self pickRepository ifNil: [^ self]. + + (self repository allSinkRepositories includes: targetRepository) ifTrue: [ + self notify: (String streamContents: [:stream | + stream nextPutAll: 'Versions from this repository should only be moved, not copied.' translated. + (self repository isKindOf: MCHttpRepository) ifTrue: [ + stream space; nextPutAll: ('Instead, use the web interface via {1} to manage contributions.' translated format: {(Url absoluteFromText: self repository description) + path: ''; + downloadUrl})]. + stream cr; cr; nextPutAll: 'Do you want to proceed anyway?' withCRs translated])]. + + repository storeVersion: self version.! - self pickRepository ifNotNil: - [:repository | - (self repository = MCRepository inbox and: - [repository = MCRepository trunk or: [repository = MCRepository treated]]) ifTrue: - [self notify: 'Versions from the inbox should only be moved, not copied. Instead, use the web interface via source.squeak.org to manage inbox contributions.\\Do you want to proceed anyway?' translated withCRs]. - repository storeVersion: self version]! Item was changed: ----- Method: MCWorkingCopyBrowser>>checkForNewerVersions (in category 'actions') ----- checkForNewerVersions + | newer | newer := workingCopy possiblyNewerVersionsIn: self repository. + (newer notEmpty ==> [ + self confirm: ('{1}\\{2}\\{3}' withCRs translated format: { + 'CAUTION!! These versions in the repository may be newer:' translated. + (newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149. + 'Do you really want to save this version?' translated}) ]) + ifFalse: [^ false]. + + self repository defaultSinkRepository ifNotNil: [:sinkRepository | + newer := workingCopy possiblyNewerVersionsIn: sinkRepository. + (newer notEmpty ==> [ + self confirm: ('{1}\\{2}\\{3}' withCRs translated format: { + 'CAUTION!! These versions in the sink repository\({1})\may be newer:' withCRs translated format: {sinkRepository description}. + (newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149. + 'Do you really want to save this version?' translated}) ]) + ifFalse: [^ false]]. + + ^ true! - ^ newer isEmpty or: [ - self confirm: 'CAUTION!! These versions in the repository may be newer:', - String cr, ((newer asCommaString withNoLineLongerThan: 150) truncateWithElipsisTo: 5 * 149), String cr, - 'Do you really want to save this version?'].! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 10:10:28 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 10:10:28 +0000 Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <1615456739100-0.post@n4.nabble.com> References: <1615235931986-0.post@n4.nabble.com> <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> <1615448018993-0.post@n4.nabble.com> <0475444a09b2428ab84955c7f70c292a@student.hpi.uni-potsdam.de>, <1615456739100-0.post@n4.nabble.com> Message-ID: <63050f212cc44495b75d3567db6e2de7@student.hpi.uni-potsdam.de> But this description is not even consistent with the idea of your #collect:selecting:stopBefore:, is it? Or should this method indeed always select at least one element? Reminds me of the difference between "while...do" and "do...until" loops. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Donnerstag, 11. März 2021 10:58:59 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... I know what you mean Christoph but I personally prefer to see the main, substantial action first and the infrequent event/stop condition last. It's like: "Go this way and do that until your reach a stop sign" ;) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 10:22:02 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 10:22:02 +0000 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> <20210311012513.GA94119@shell.msen.com>, Message-ID: <6773d6508bee4a0e863d6ae0039c550f@student.hpi.uni-potsdam.de> > Grammar rules apart, if second has to answer a unit of 1 second, why the hell send such message to 5? Why not Time second for example? Just syntactic sugar, similar to #asString instead of "String newFrom: ..." Iirc Kent Beck disrecommended the idea in general, but I like its convenience. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Nicolas Cellier Gesendet: Donnerstag, 11. März 2021 08:16:51 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Explorer / Inspector bug? Grammar rules apart, if second has to answer a unit of 1 second, why the hell send such message to 5? Why not Time second for example? Le jeu. 11 mars 2021 à 02:25, David T. Lewis > a écrit : On Tue, Mar 09, 2021 at 01:47:49PM +0000, Thiede, Christoph wrote: > > "I want a two second delay" is perfectly valid :D > > Maybe a native English speaker can correct me but afaik, in the grammar > dependency tree of "two-second delay", "two-second" is not an independet > noun but a pre-modifying phrase only. Shall we really start to support > even more different types of words in an object-oriented language like > Smalltalk? Imho, substantives and verbs are already enough. :-) > I am a native Engish speaker with a poor understanding of grammar, so that makes me a good person to attempt an answer ;-) The use of singular "second" or plural "seconds" may depend on the context of the expression, but in any case if I were to hear someone say "five second" I would understand it to refer to five seconds, not one second. If I were to try to enforce correct English (is there such a thing? of course not), then I might try to treat "five second" as an error. But we do not really need to enforce English syntax rules, and in this case it is more important for the expression to do the right thing. So for me as an English speaker, I overlook the difference between "second" and "seconds" and I prefer to have the expression do what I expect in either case. For this reason, it makes sense to me for #second and #seconds to be treated as synonyms. Dave -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Thu Mar 11 10:22:46 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 11 Mar 2021 10:22:46 0000 Subject: [squeak-dev] The Inbox: Kernel-jar.1381.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-jar.1381.mcz ==================== Summary ==================== Name: Kernel-jar.1381 Author: jar Time: 11 March 2021, 11:22:42.897307 am UUID: 692824e3-388b-7a4c-98ca-03fcacdc8b37 Ancestors: Kernel-mt.1380 Fix a bug in Process #isTerminated and #isSuspended. The issue has also shown recently on an issue http://forum.world.st/Bug-in-Process-gt-gt-terminate-Returning-from-unwind-contexts-td5127570.html where it was causing terminated processes remain in Process Browser (erroneously considering them not terminated). The main threads discussing this are: http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html#a5127336 http://forum.world.st/The-Inbox-Kernel-jar-1380-mcz-td5127524.html =============== Diff against Kernel-mt.1380 =============== Item was changed: ----- Method: Process>>isSuspended (in category 'testing') ----- isSuspended + "A process is suspended if it has non-nil suspendedContext (e.g. new or + previously suspended with the suspend primitive) and is not terminated or + waiting in a scheduler or a semaphore queue (i.e. is not runnable or blocked)." + + ^myList isNil + and: [suspendedContext notNil] + and: [self isTerminated not]! - "A process is suspended if it has been suspended with the suspend primitive. - It is distinguishable from the active process and a terminated process by - having a non-nil suspendedContext that is either not the bottom context - or has not reached its endPC." - ^nil == myList - and: [nil ~~ suspendedContext - and: [suspendedContext isBottomContext - ifTrue: [suspendedContext closure - ifNil: [suspendedContext methodClass ~~ Process - or: [suspendedContext selector ~~ #terminate]] - ifNotNil: [suspendedContext pc < suspendedContext closure endPC]] - ifFalse: [true]]]! Item was changed: ----- Method: Process>>isTerminated (in category 'testing') ----- isTerminated "Answer if the receiver is terminated, or at least terminating." self isActiveProcess ifTrue: [^ false]. ^suspendedContext isNil + or: ["If the suspendedContext is the bottomContext and the pc is at the endPC, + then there is nothing more to do." - or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess. - If so, and the pc is at the endPC, the block has already sent and returned - from value and there is nothing more to do." suspendedContext isBottomContext + and: [suspendedContext pc >= suspendedContext endPC + or: [suspendedContext closure isNil + and: [suspendedContext methodClass == Process + and: [suspendedContext selector == #terminate]]]]]! - and: [suspendedContext closure - ifNil: [suspendedContext methodClass == Process - and: [suspendedContext selector == #terminate]] - ifNotNil: [suspendedContext pc >= suspendedContext closure endPC]]]! From m at jaromir.net Thu Mar 11 10:38:47 2021 From: m at jaromir.net (Jaromir Matas) Date: Thu, 11 Mar 2021 04:38:47 -0600 (CST) Subject: [squeak-dev] Collections/Streams | About enumerating a sequence up to a matching query ... In-Reply-To: <63050f212cc44495b75d3567db6e2de7@student.hpi.uni-potsdam.de> References: <9dfebbd3057c434589c3527b8fceebdf@student.hpi.uni-potsdam.de> <1615448018993-0.post@n4.nabble.com> <0475444a09b2428ab84955c7f70c292a@student.hpi.uni-potsdam.de> <1615456739100-0.post@n4.nabble.com> <63050f212cc44495b75d3567db6e2de7@student.hpi.uni-potsdam.de> Message-ID: <1615459127640-0.post@n4.nabble.com> > Reminds me of the difference between "while...do" and "do...until" loops. > :-) True, I never know and always have to doublecheck :) Ok, I'll change the wording: aCaseOfBeers collect: [:each | self drink: each] selecting: #lager stopBefore: #isMidnight assuming `self drink` returns the empty bottle ;) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From lists at fniephaus.com Thu Mar 11 12:46:05 2021 From: lists at fniephaus.com (Fabio Niephaus) Date: Thu, 11 Mar 2021 13:46:05 +0100 Subject: [squeak-dev] Squeak on GraalVM live on Twitch today (2021-03-11) Message-ID: Hi all, Thomas Würthinger, the founder of GraalVM, and I will be talking about Squeak, TruffleSqueak, and GraalVM today. In an interactive session, we'll explore GraalVM with Squeak at run-time, show some demos, and talk about polyglot programming. You can join us live on Twitch today at around 6:30pm CET / 9:30am PST: https://twitch.tv/thomaswue Cheers, Fabio From commits at source.squeak.org Thu Mar 11 12:50:14 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 11 Mar 2021 12:50:14 0000 Subject: [squeak-dev] The Inbox: Compiler-tobe.455.mcz Message-ID: A new version of Compiler was added to project The Inbox: http://source.squeak.org/inbox/Compiler-tobe.455.mcz ==================== Summary ==================== Name: Compiler-tobe.455 Author: tobe Time: 11 March 2021, 1:50:12.615385 pm UUID: ba3e2f61-8c2a-4dcf-a288-f6e81db4eda1 Ancestors: Compiler-codefrau.454 Fix scanAllTokenPositionsInto: when the text of a comment happened to appear just before it. See testScanTokensRepeatComment for an example. =============== Diff against Compiler-codefrau.454 =============== Item was changed: ----- Method: Scanner>>scanAllTokenPositionsInto: (in category 'expression types') ----- scanAllTokenPositionsInto: aBlock "Evaluate aBlock with the start and end positions of all separate non-white-space tokens, including comments." | lastMark | lastMark := 1. [currentComment ifNotNil: [currentComment do: [:cmnt| | idx | + idx := source originalContents findLastOccurrenceOfString: cmnt startingAt: lastMark. - idx := source originalContents indexOfSubCollection: cmnt startingAt: lastMark. (idx > 0 and: [idx < mark]) ifTrue: [aBlock value: idx - 1 value: (lastMark := idx + cmnt size)]]. currentComment := nil]. mark ifNotNil: [(token == #- and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: [| savedMark | savedMark := mark. self scanToken. token := token negated. mark := savedMark]. "Compensate for the fact that the parser uses two character lookahead. Normally we must remove the extra two characters. But this mustn't happen for the last token at the end of stream." aBlock value: mark value: source position - (aheadChar == DoItCharacter ifTrue: [hereChar == DoItCharacter ifTrue: [0] ifFalse: [1]] ifFalse: [2])]. (tokenType == #rightParenthesis or: [tokenType == #doIt]) ifTrue: [^self]. tokenType == #leftParenthesis ifTrue: [self scanToken; scanAllTokenPositionsInto: aBlock] ifFalse: [(tokenType == #word or: [tokenType == #keyword or: [tokenType == #colon]]) ifTrue: [self scanLitWord. token == #true ifTrue: [token := true]. token == #false ifTrue: [token := false]. token == #nil ifTrue: [token := nil]] ifFalse: [(token == #- and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: [self scanToken. token := token negated]]]. self scanToken ] repeat! From commits at source.squeak.org Thu Mar 11 12:51:23 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 11 Mar 2021 12:51:23 0000 Subject: [squeak-dev] The Inbox: Tests-tobe.445.mcz Message-ID: A new version of Tests was added to project The Inbox: http://source.squeak.org/inbox/Tests-tobe.445.mcz ==================== Summary ==================== Name: Tests-tobe.445 Author: tobe Time: 11 March 2021, 1:51:19.457627 pm UUID: e5547bc0-8f7f-4880-b3bc-a18fdb625c3b Ancestors: Tests-mt.444 Complements Compiler-tobe.455 =============== Diff against Tests-mt.444 =============== Item was added: + ----- Method: ScannerTest>>testScanTokensRepeatingComment (in category 'tests') ----- + testScanTokensRepeatingComment + + | ranges | + ranges := Array streamContents: [:stream | + Scanner new scanTokenPositionsIn: '''packages''. "packages" 222' into: [:start :end | stream nextPut: (start to: end)]]. + + self assert: (ranges hasEqualElements: {1 to: 10. 11 to: 11. 13 to: 22. 24 to: 26. (27 to: 26)})! From commits at source.squeak.org Thu Mar 11 13:12:06 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 11 Mar 2021 13:12:06 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1740.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1740.mcz ==================== Summary ==================== Name: Morphic-mt.1740 Author: mt Time: 11 March 2021, 2:11:59.965436 pm UUID: 3512b5b2-7e73-134e-ae42-dfedc359858f Ancestors: Morphic-mt.1739 Minor clean-up in initial halo dispatch: - Do not ask for #handlesMouseDown: but only #wantsHaloFromClick. - Do not rely on aContainer being the actual world (e.g. aPasteUp) but maybe any (inner) container. - Leave two assertions as documentation. Effective rules for halo dispatch not changed. The bug with protruding submorphs is still present. =============== Diff against Morphic-mt.1739 =============== Item was changed: ----- Method: MorphicHaloDispatcher>>dispatchHalo:createFor: (in category 'dispatching') ----- + dispatchHalo: anEvent createFor: aContainer + "Invoke a halo on any aContainer's submorph that wants it. Dispatch uses anEvent's #position. The dispatch only ends in that container if no other morph wants it. Note that the event's #shiftPressed state determines whether the dispatch goes innermost-to-outermost (if pressed) or the other way around (if not pressed). + + If there already is a halo, check whether the event still points into the same hierarchy. If it does, do nothing here but rely on the halo itself to process the event (see implementors of #transferHalo:from:). If, however, the event points to a different hierarchy in the container, invoke a new halo and discard the current one. We do this here because the current halo should not bother with its container but only its #target." - dispatchHalo: anEvent createFor: aMorph - "Invoke halos around the top-most world container at aUserInputEvent's #position. If it was already halo'd, zero-in on its next inward component morph at that position. Holding Shift during the click reverses this traversal order." | stack innermost haloTarget | + "The stack is the frontmost (i.e. innermost) to backmost (i.e. outermost) morph." + stack := (aContainer morphsAt: anEvent position unlocked: true) select: + [ : each | each wantsHaloFromClick ]. + "self assert: [ stack last == aContainer ]." - "the stack is the top-most morph to bottom-most." - stack := (aMorph morphsAt: anEvent position unlocked: true) select: - [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: anEvent ] ]. innermost := anEvent hand halo ifNil: [ stack first ] ifNotNil: + [ : existingHalo | + "self assert: [ existingHalo wantsHaloFromClick not ]. " + stack + detect: [ : each | each owner == aContainer ] - [ : existingHalo | - (stack := stack copyWithout: existingHalo) "No halos on halos" - detect: [ : each | each owner == aMorph ] ifFound: + [ : topInContainer | "Is existingHalo's target part of the same topInContainer as the morph clicked?" + (existingHalo target withAllOwners includes: topInContainer) - [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?" - (existingHalo target withAllOwners includes: worldContainer) ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now." ^ false ] ifFalse: [ "different hierarchy, remove + add." anEvent hand removeHalo. anEvent shiftPressed ifTrue: [ stack first ] + ifFalse: [ topInContainer ] ] ] - ifFalse: [ worldContainer ] ] ] ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now." ^ false ] ]. "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))." + haloTarget := (innermost == aContainer or: [ anEvent shiftPressed ]) - haloTarget := (innermost == aMorph or: [anEvent shiftPressed]) ifTrue: [ innermost ] ifFalse: + [ "Find the outermost owner that wants it. Ignore containment above aContainer." + stack := innermost withAllOwners. + (stack first: (stack findFirst: [ : each | each owner == aContainer ])) reversed - [ "Find the outermost owner that wants it." - innermost withAllOwners reversed allButFirst detect: [ : each | each wantsHaloFromClick ] ifNone: [ "haloTarget has its own mouseDown handler, don't halo." ^ false ] ]. "Now that we have the haloTarget, show the halo." self invokeHaloOrMove: anEvent on: haloTarget. ^ true! From marcel.taeumel at hpi.de Thu Mar 11 13:23:11 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 11 Mar 2021 14:23:11 +0100 Subject: [squeak-dev] The Inbox: Monticello-ct.739.mcz In-Reply-To: References: Message-ID: Hi Christoph, how can a selection ever be "nil" when using the context menu in a save dialog or patch browser? This only works for a specific combination of system preferences, I suppose :-)  [x] Always show v scroll bar [ ] Scroll bars without menu button Or just [ ] Menu request updates list/tree selection Hmmm... Best, Marcel Am 10.03.2021 18:55:14 schrieb commits at source.squeak.org : A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.739.mcz ==================== Summary ==================== Name: Monticello-ct.739 Author: ct Time: 10 March 2021, 6:55:01.889559 pm UUID: aec2f89c-cf99-ea47-91f4-4cdf2ebd5bb9 Ancestors: Monticello-mt.736 Tweaks 'add to current change set' command to create a changeset from all (non-ignored) items in an operations browser. Also hides the 'browse full' command from the menu if not any item is selected since it does not have any function in this case. =============== Diff against Monticello-mt.736 =============== Item was changed: ----- Method: MCCodeTool>>methodListMenu: (in category 'menus') ----- methodListMenu: aMenu "Build the menu for the selected method, if any." self selectedMessageName ifNil: [items notEmpty ifTrue: [aMenu addList:#( - ('browse full (b)' browseMethodFull) ('fileOut (o)' fileOutMessage))]] ifNotNil: [ aMenu addList:#( ('browse full (b)' browseMethodFull) ('browse hierarchy (h)' browseClassHierarchy) ('browse protocol (p)' browseFullProtocol) - ('fileOut (o)' fileOutMessage) ('printOut' printOutMessage) ('copy selector (c)' copySelector) ('copy reference (C)' copyReference)). aMenu addList: #( - ('browse senders (n)' browseSendersOfMessages) ('browse implementors (m)' browseMessages) ('inheritance (i)' methodHierarchy) ('versions (v)' browseVersions) ('change sets with this method' findMethodInChangeSets) " ('x revert to previous version' revertToPreviousVersion)" ('remove from current change set' removeFromCurrentChanges) " ('x revert & remove from changes' revertAndForget)" ('add to current change set' adoptMessageInCurrentChangeset) " ('x copy up or copy down...' copyUpOrCopyDown)" " ('x remove method (x)' removeMessage)" "-" ). ]. " aMenu addList: #( ('x inst var refs...' browseInstVarRefs) ('x inst var defs...' browseInstVarDefs) ('x class var refs...' browseClassVarRefs) ('x class variables' browseClassVariables) ('x class refs (N)' browseClassRefs) ). " ^ aMenu ! Item was added: + ----- Method: MCOperationsBrowser>>adoptMessageInCurrentChangeset (in category 'menus') ----- + adoptMessageInCurrentChangeset + + selection ifNotNil: [^ super adoptMessageInCurrentChangeset]. + + items do: [:item | + self forItem: item setClassAndSelectorIn: [:class :selector | + ChangeSet current adoptSelector: selector forClass: class]]. + self changed: #annotations.! Item was added: + ----- Method: MCOperationsBrowser>>forItem:setClassAndSelectorIn: (in category 'private') ----- + forItem: item setClassAndSelectorIn: classSelectorBlock + + item definition isMethodDefinition ifFalse: [self halt]. + ^ classSelectorBlock + value: item definition actualClass + value: item definition selector! Item was changed: ----- Method: MCOperationsBrowser>>methodListMenu: (in category 'menus') ----- methodListMenu: aMenu + selection + ifNil: [items ifNotEmpty: [ + aMenu addList: #( + ('add to current change set' adoptMessageInCurrentChangeset))]] + ifNotNil: [aMenu addList: #( - selection ifNotNil: - [aMenu addList: #( ('install' installSelection) ('revert (x)' revertSelection) ('browse origin' browseSelectionOrigin) -)]. self unchangedMethods ifNotEmpty: [aMenu addList: #( ('revert unchanged methods...' revertUnchangedMethods) ('filter out unchanged methods...' filterOutUnchangedMethods) -)]. super methodListMenu: aMenu. ^ aMenu! Item was added: + ----- Method: MCSaveVersionDialog>>adoptMessageInCurrentChangeset (in category 'menus') ----- + adoptMessageInCurrentChangeset + + selection ifNotNil: [^ super adoptMessageInCurrentChangeset]. + + (items copyWithoutAll: ignore) do: [:item | + self forItem: item setClassAndSelectorIn: [:class :selector | + ChangeSet current adoptSelector: selector forClass: class]]. + self changed: #annotations.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 14:29:39 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 14:29:39 +0000 Subject: [squeak-dev] The Inbox: Monticello-ct.739.mcz In-Reply-To: References: , Message-ID: Hi Marcel, I use this every day, it's pretty simple and very helpful: Just press Escape to open the context menu when no item is selected. :D However, it might be helpful if you had a "mouse way" to do the same thing ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Donnerstag, 11. März 2021 14:23:11 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Monticello-ct.739.mcz Hi Christoph, how can a selection ever be "nil" when using the context menu in a save dialog or patch browser? This only works for a specific combination of system preferences, I suppose :-) [x] Always show v scroll bar [ ] Scroll bars without menu button Or just [ ] Menu request updates list/tree selection Hmmm... Best, Marcel Am 10.03.2021 18:55:14 schrieb commits at source.squeak.org : A new version of Monticello was added to project The Inbox: http://source.squeak.org/inbox/Monticello-ct.739.mcz ==================== Summary ==================== Name: Monticello-ct.739 Author: ct Time: 10 March 2021, 6:55:01.889559 pm UUID: aec2f89c-cf99-ea47-91f4-4cdf2ebd5bb9 Ancestors: Monticello-mt.736 Tweaks 'add to current change set' command to create a changeset from all (non-ignored) items in an operations browser. Also hides the 'browse full' command from the menu if not any item is selected since it does not have any function in this case. =============== Diff against Monticello-mt.736 =============== Item was changed: ----- Method: MCCodeTool>>methodListMenu: (in category 'menus') ----- methodListMenu: aMenu "Build the menu for the selected method, if any." self selectedMessageName ifNil: [items notEmpty ifTrue: [aMenu addList:#( - ('browse full (b)' browseMethodFull) ('fileOut (o)' fileOutMessage))]] ifNotNil: [ aMenu addList:#( ('browse full (b)' browseMethodFull) ('browse hierarchy (h)' browseClassHierarchy) ('browse protocol (p)' browseFullProtocol) - ('fileOut (o)' fileOutMessage) ('printOut' printOutMessage) ('copy selector (c)' copySelector) ('copy reference (C)' copyReference)). aMenu addList: #( - ('browse senders (n)' browseSendersOfMessages) ('browse implementors (m)' browseMessages) ('inheritance (i)' methodHierarchy) ('versions (v)' browseVersions) ('change sets with this method' findMethodInChangeSets) " ('x revert to previous version' revertToPreviousVersion)" ('remove from current change set' removeFromCurrentChanges) " ('x revert & remove from changes' revertAndForget)" ('add to current change set' adoptMessageInCurrentChangeset) " ('x copy up or copy down...' copyUpOrCopyDown)" " ('x remove method (x)' removeMessage)" "-" ). ]. " aMenu addList: #( ('x inst var refs...' browseInstVarRefs) ('x inst var defs...' browseInstVarDefs) ('x class var refs...' browseClassVarRefs) ('x class variables' browseClassVariables) ('x class refs (N)' browseClassRefs) ). " ^ aMenu ! Item was added: + ----- Method: MCOperationsBrowser>>adoptMessageInCurrentChangeset (in category 'menus') ----- + adoptMessageInCurrentChangeset + + selection ifNotNil: [^ super adoptMessageInCurrentChangeset]. + + items do: [:item | + self forItem: item setClassAndSelectorIn: [:class :selector | + ChangeSet current adoptSelector: selector forClass: class]]. + self changed: #annotations.! Item was added: + ----- Method: MCOperationsBrowser>>forItem:setClassAndSelectorIn: (in category 'private') ----- + forItem: item setClassAndSelectorIn: classSelectorBlock + + item definition isMethodDefinition ifFalse: [self halt]. + ^ classSelectorBlock + value: item definition actualClass + value: item definition selector! Item was changed: ----- Method: MCOperationsBrowser>>methodListMenu: (in category 'menus') ----- methodListMenu: aMenu + selection + ifNil: [items ifNotEmpty: [ + aMenu addList: #( + ('add to current change set' adoptMessageInCurrentChangeset))]] + ifNotNil: [aMenu addList: #( - selection ifNotNil: - [aMenu addList: #( ('install' installSelection) ('revert (x)' revertSelection) ('browse origin' browseSelectionOrigin) -)]. self unchangedMethods ifNotEmpty: [aMenu addList: #( ('revert unchanged methods...' revertUnchangedMethods) ('filter out unchanged methods...' filterOutUnchangedMethods) -)]. super methodListMenu: aMenu. ^ aMenu! Item was added: + ----- Method: MCSaveVersionDialog>>adoptMessageInCurrentChangeset (in category 'menus') ----- + adoptMessageInCurrentChangeset + + selection ifNotNil: [^ super adoptMessageInCurrentChangeset]. + + (items copyWithoutAll: ignore) do: [:item | + self forItem: item setClassAndSelectorIn: [:class :selector | + ChangeSet current adoptSelector: selector forClass: class]]. + self changed: #annotations.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 14:35:22 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 14:35:22 +0000 Subject: [squeak-dev] The Inbox: Compiler-tobe.455.mcz In-Reply-To: References: Message-ID: <23e64136e3ea4c9bb80a773867b583be@student.hpi.uni-potsdam.de> Nice catch! Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Donnerstag, 11. März 2021 13:50:14 An: squeak-dev at lists.squeakfoundation.org Betreff: [squeak-dev] The Inbox: Compiler-tobe.455.mcz A new version of Compiler was added to project The Inbox: http://source.squeak.org/inbox/Compiler-tobe.455.mcz ==================== Summary ==================== Name: Compiler-tobe.455 Author: tobe Time: 11 March 2021, 1:50:12.615385 pm UUID: ba3e2f61-8c2a-4dcf-a288-f6e81db4eda1 Ancestors: Compiler-codefrau.454 Fix scanAllTokenPositionsInto: when the text of a comment happened to appear just before it. See testScanTokensRepeatComment for an example. =============== Diff against Compiler-codefrau.454 =============== Item was changed: ----- Method: Scanner>>scanAllTokenPositionsInto: (in category 'expression types') ----- scanAllTokenPositionsInto: aBlock "Evaluate aBlock with the start and end positions of all separate non-white-space tokens, including comments." | lastMark | lastMark := 1. [currentComment ifNotNil: [currentComment do: [:cmnt| | idx | + idx := source originalContents findLastOccurrenceOfString: cmnt startingAt: lastMark. - idx := source originalContents indexOfSubCollection: cmnt startingAt: lastMark. (idx > 0 and: [idx < mark]) ifTrue: [aBlock value: idx - 1 value: (lastMark := idx + cmnt size)]]. currentComment := nil]. mark ifNotNil: [(token == #- and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: [| savedMark | savedMark := mark. self scanToken. token := token negated. mark := savedMark]. "Compensate for the fact that the parser uses two character lookahead. Normally we must remove the extra two characters. But this mustn't happen for the last token at the end of stream." aBlock value: mark value: source position - (aheadChar == DoItCharacter ifTrue: [hereChar == DoItCharacter ifTrue: [0] ifFalse: [1]] ifFalse: [2])]. (tokenType == #rightParenthesis or: [tokenType == #doIt]) ifTrue: [^self]. tokenType == #leftParenthesis ifTrue: [self scanToken; scanAllTokenPositionsInto: aBlock] ifFalse: [(tokenType == #word or: [tokenType == #keyword or: [tokenType == #colon]]) ifTrue: [self scanLitWord. token == #true ifTrue: [token := true]. token == #false ifTrue: [token := false]. token == #nil ifTrue: [token := nil]] ifFalse: [(token == #- and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: [self scanToken. token := token negated]]]. self scanToken ] repeat! -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicolas.cellier.aka.nice at gmail.com Thu Mar 11 15:22:43 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Thu, 11 Mar 2021 16:22:43 +0100 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <6773d6508bee4a0e863d6ae0039c550f@student.hpi.uni-potsdam.de> References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> <20210311012513.GA94119@shell.msen.com> <6773d6508bee4a0e863d6ae0039c550f@student.hpi.uni-potsdam.de> Message-ID: With asString, we ask the object itself to convert as String. It can very well have its own idea how to do it. In case of second, it's a different thing, it acts on behalf of another object, without using the slightest ounce of own identity... Le jeu. 11 mars 2021 à 11:22, Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> a écrit : > > Grammar rules apart, if second has to answer a unit of 1 second, why > the hell send such message to 5? Why not Time second for example? > > Just syntactic sugar, similar to #asString instead of "String newFrom: > ..." Iirc Kent Beck disrecommended the idea in general, but I like its > convenience. :-) > > Best, > Christoph > > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Nicolas Cellier > *Gesendet:* Donnerstag, 11. März 2021 08:16:51 > *An:* The general-purpose Squeak developers list > *Betreff:* Re: [squeak-dev] Explorer / Inspector bug? > > Grammar rules apart, if second has to answer a unit of 1 second, why the > hell send such message to 5? Why not Time second for example? > > Le jeu. 11 mars 2021 à 02:25, David T. Lewis a > écrit : > >> On Tue, Mar 09, 2021 at 01:47:49PM +0000, Thiede, Christoph wrote: >> > > "I want a two second delay" is perfectly valid :D >> > >> > Maybe a native English speaker can correct me but afaik, in the grammar >> > dependency tree of "two-second delay", "two-second" is not an independet >> > noun but a pre-modifying phrase only. Shall we really start to support >> > even more different types of words in an object-oriented language like >> > Smalltalk? Imho, substantives and verbs are already enough. :-) >> > >> >> I am a native Engish speaker with a poor understanding of grammar, so >> that makes me a good person to attempt an answer ;-) >> >> The use of singular "second" or plural "seconds" may depend on the >> context of the expression, but in any case if I were to hear someone >> say "five second" I would understand it to refer to five seconds, not >> one second. If I were to try to enforce correct English (is there such >> a thing? of course not), then I might try to treat "five second" as >> an error. But we do not really need to enforce English syntax rules, >> and in this case it is more important for the expression to do the >> right thing. >> >> So for me as an English speaker, I overlook the difference between >> "second" and "seconds" and I prefer to have the expression do what >> I expect in either case. >> >> For this reason, it makes sense to me for #second and #seconds to >> be treated as synonyms. >> >> Dave >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicolas.cellier.aka.nice at gmail.com Thu Mar 11 15:25:24 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Thu, 11 Mar 2021 16:25:24 +0100 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1614969432339-0.post@n4.nabble.com> <1614985659729-0.post@n4.nabble.com> <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> <20210311012513.GA94119@shell.msen.com> <6773d6508bee4a0e863d6ae0039c550f@student.hpi.uni-potsdam.de> Message-ID: The only objects whose opinion differ on what second should answer are SequenceableCollection, but that's a case of false polymorphism ;) Le jeu. 11 mars 2021 à 16:22, Nicolas Cellier < nicolas.cellier.aka.nice at gmail.com> a écrit : > With asString, we ask the object itself to convert as String. It can very > well have its own idea how to do it. In case of second, it's a different > thing, it acts on behalf of another object, without using the slightest > ounce of own identity... > > Le jeu. 11 mars 2021 à 11:22, Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> a écrit : > >> > Grammar rules apart, if second has to answer a unit of 1 second, why >> the hell send such message to 5? Why not Time second for example? >> >> Just syntactic sugar, similar to #asString instead of "String newFrom: >> ..." Iirc Kent Beck disrecommended the idea in general, but I like its >> convenience. :-) >> >> Best, >> Christoph >> >> ------------------------------ >> *Von:* Squeak-dev im >> Auftrag von Nicolas Cellier >> *Gesendet:* Donnerstag, 11. März 2021 08:16:51 >> *An:* The general-purpose Squeak developers list >> *Betreff:* Re: [squeak-dev] Explorer / Inspector bug? >> >> Grammar rules apart, if second has to answer a unit of 1 second, why the >> hell send such message to 5? Why not Time second for example? >> >> Le jeu. 11 mars 2021 à 02:25, David T. Lewis a >> écrit : >> >>> On Tue, Mar 09, 2021 at 01:47:49PM +0000, Thiede, Christoph wrote: >>> > > "I want a two second delay" is perfectly valid :D >>> > >>> > Maybe a native English speaker can correct me but afaik, in the grammar >>> > dependency tree of "two-second delay", "two-second" is not an >>> independet >>> > noun but a pre-modifying phrase only. Shall we really start to support >>> > even more different types of words in an object-oriented language like >>> > Smalltalk? Imho, substantives and verbs are already enough. :-) >>> > >>> >>> I am a native Engish speaker with a poor understanding of grammar, so >>> that makes me a good person to attempt an answer ;-) >>> >>> The use of singular "second" or plural "seconds" may depend on the >>> context of the expression, but in any case if I were to hear someone >>> say "five second" I would understand it to refer to five seconds, not >>> one second. If I were to try to enforce correct English (is there such >>> a thing? of course not), then I might try to treat "five second" as >>> an error. But we do not really need to enforce English syntax rules, >>> and in this case it is more important for the expression to do the >>> right thing. >>> >>> So for me as an English speaker, I overlook the difference between >>> "second" and "seconds" and I prefer to have the expression do what >>> I expect in either case. >>> >>> For this reason, it makes sense to me for #second and #seconds to >>> be treated as synonyms. >>> >>> Dave >>> >>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Thu Mar 11 17:01:55 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Thu, 11 Mar 2021 18:01:55 +0100 Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation Message-ID: Hi all! Christoph put in a lot of effort to figure out the cause of infinite debugger chains under various circumstances. He is curious how far "debugging the debugger" can work and how possible improvements to code simulation might look like. We basically figured out that the debugger that pops up from an unhandled error (or warning) must never try debugging a simulated process but always the "genuine process", which is the one that is actually running and which may do the code simulation for another process. Please find attached a change set with that fix. Tests are in "DebuggerTests" and "ProcessTest". The most interesting methods are ProcessorScheduler >> #debugContext:title:full:contents: and Process >> #debugWithTitle:full:contents:. Please take a look at their comments. We will merge this into Trunk in a some days, given that there are no objections. :-) Related discussions: http://forum.world.st/I-broke-the-debugger-tp5110752p5110814.html [http://forum.world.st/I-broke-the-debugger-tp5110752p5110814.html] http://forum.world.st/The-Inbox-Morphic-ct-1610-mcz-tp5108228.html [http://forum.world.st/The-Inbox-Morphic-ct-1610-mcz-tp5108228.html] Best, Marcel and Christoph P.S.: Debugging a dialog invocation looks nicer now. Try it out. -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 13738 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: use-genuine-process-to-fix-simulation.2.cs Type: application/octet-stream Size: 35325 bytes Desc: not available URL: From lewis at mail.msen.com Thu Mar 11 17:34:14 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Thu, 11 Mar 2021 12:34:14 -0500 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: References: <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> <20210311012513.GA94119@shell.msen.com> <6773d6508bee4a0e863d6ae0039c550f@student.hpi.uni-potsdam.de> Message-ID: <20210311173414.GA42817@shell.msen.com> On Thu, Mar 11, 2021 at 04:25:24PM +0100, Nicolas Cellier wrote: > The only objects whose opinion differ on what second should answer are > SequenceableCollection, but that's a case of false polymorphism ;) > Maybe we should have 1 second ==> 2 ;-) Dave From tim at rowledge.org Thu Mar 11 17:58:33 2021 From: tim at rowledge.org (tim Rowledge) Date: Thu, 11 Mar 2021 09:58:33 -0800 Subject: [squeak-dev] Explorer / Inspector bug? In-Reply-To: <20210311173414.GA42817@shell.msen.com> References: <1615019684983-0.post@n4.nabble.com> <20210306150521.GA34636@shell.msen.com> <74C9314E-87B0-484C-8115-A502539EA909@gmx.de> <67d14c7d401c4b9fbf016a1618ff7ecb@student.hpi.uni-potsdam.de> <20210311012513.GA94119@shell.msen.com> <6773d6508bee4a0e863d6ae0039c550f@student.hpi.uni-potsdam.de> <20210311173414.GA42817@shell.msen.com> Message-ID: <5AF1B463-FC09-4397-B791-47103A7937D8@rowledge.org> > On 2021-03-11, at 9:34 AM, David T. Lewis wrote: > > On Thu, Mar 11, 2021 at 04:25:24PM +0100, Nicolas Cellier wrote: >> The only objects whose opinion differ on what second should answer are >> SequenceableCollection, but that's a case of false polymorphism ;) >> > > Maybe we should have > > 1 second ==> 2 I'll second that tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Why use one word when two polysyllabic agglomerates will do? From Christoph.Thiede at student.hpi.uni-potsdam.de Thu Mar 11 18:52:14 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Thu, 11 Mar 2021 18:52:14 +0000 Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: References: Message-ID: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> Thanks a lot for the collaboration, Marcel! :-) > We basically figured out that the debugger that pops up from an unhandled error (or warning) must never try debugging a simulated process but always the "genuine process", which is the one that is actually running and which may do the code simulation for another process. A small summary of this bug for all interested readers who are not yet familiar with the debugging machinery: The actual issue causing all the debugger chains was a mechanism called process-faithful debugging. In a nutshell, it makes sure that when you debug an expression such as "Process activeProcess", the expression answers the correct process instance even when being debugged (that is, it must answer the process being debugged instead of the debugger process which is responsible for the debugging). Process-faithful debugging works by redirecting all sends to ProcessorScheduler >> #activeProcess to a so-called #effectiveProcess. However, when some error occurred in the debugging process during a debugging step (that is, a simulation error such as [1] [2] occurred), a second debugger was opened - but because #activeProcess was just being subjected to redirection, this second debugger did not interrupt the debugging process but the process being debugged instead. As a consequence, the faulty debugging process kept running and was given the opportunity to do any other harm. If you now take a look into how Object >> #at: or Object >> #doesNotUnderstand: are implemented (that is, by unlimited recursion), you will see that it could fire one debugger after the next one this way, without limitation, causing the infinite debugger chains that broke your images. The solution, in its simplest form, was pretty straightforward: When opening a debugger from an error (see StandardToolSet >> #handleError: and others), make sure not to honor process-faithful debugging but always open the debugger on the actually running process, which we decided to call genuineProcess for sake of differentiation from #activeProcess. The rest of the changeset focuses on some additional refactoring of the overall debugging API on Process and ProcessorScheduler, striving to make it more intuitive for application developers to choose the right process and context for debugging. If you want to learn even more details, the first thread provided by Marcel should be quite interesting (though also quite long). Otherwise, we'll be here for your questions. :-) What an interesting project this has been! I'm already looking forward to the next one! :-) Best, Christoph [1] http://forum.world.st/The-Trunk-Kernel-ct-1357-mcz-td5124373.html [2] http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-nextPut-tp5108125.html ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Donnerstag, 11. März 2021 18:01:55 An: squeak-dev Betreff: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation Hi all! Christoph put in a lot of effort to figure out the cause of infinite debugger chains under various circumstances. He is curious how far "debugging the debugger" can work and how possible improvements to code simulation might look like. We basically figured out that the debugger that pops up from an unhandled error (or warning) must never try debugging a simulated process but always the "genuine process", which is the one that is actually running and which may do the code simulation for another process. Please find attached a change set with that fix. Tests are in "DebuggerTests" and "ProcessTest". The most interesting methods are ProcessorScheduler >> #debugContext:title:full:contents: and Process >> #debugWithTitle:full:contents:. Please take a look at their comments. We will merge this into Trunk in a some days, given that there are no objections. :-) Related discussions: http://forum.world.st/I-broke-the-debugger-tp5110752p5110814.html http://forum.world.st/The-Inbox-Morphic-ct-1610-mcz-tp5108228.html Best, Marcel and Christoph P.S.: Debugging a dialog invocation looks nicer now. Try it out. [cid:88c0dc63-3136-44f8-9b3a-fd5e947e85be] -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 13738 bytes Desc: image.png URL: From commits at source.squeak.org Thu Mar 11 22:44:44 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 11 Mar 2021 22:44:44 0000 Subject: [squeak-dev] The Inbox: Collections-dtl.931.mcz Message-ID: A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-dtl.931.mcz ==================== Summary ==================== Name: Collections-dtl.931 Author: dtl Time: 11 March 2021, 5:44:43.577146 pm UUID: 1ed239e3-d108-43c3-8b6e-de8c43d842d1 Ancestors: Collections-nice.930 Set logic methods should be discoverable, so give them a method category. Add an implementation of Collection>>symmetricDifference: so that the basic set operations of union, intersection, difference, and symmetric difference are available. =============== Diff against Collections-nice.930 =============== Item was changed: + ----- Method: Collection>>difference: (in category 'set logic') ----- - ----- Method: Collection>>difference: (in category 'enumerating') ----- difference: aCollection "Answer the set theoretic difference of two collections." ^ self reject: [:each | aCollection includes: each]! Item was changed: + ----- Method: Collection>>intersection: (in category 'set logic') ----- - ----- Method: Collection>>intersection: (in category 'enumerating') ----- intersection: aCollection "Answer the set theoretic intersection of two collections." ^ self select: [:each | aCollection includes: each]! Item was added: + ----- Method: Collection>>symmetricDifference: (in category 'set logic') ----- + symmetricDifference: aCollection + "Answer the set theoretic symmetric difference of two collections." + + ^ (self difference: aCollection) union: (aCollection difference: self) + ! Item was changed: + ----- Method: Collection>>union: (in category 'set logic') ----- - ----- Method: Collection>>union: (in category 'enumerating') ----- union: aCollection "Answer the set theoretic union of two collections." ^ self asSet addAll: aCollection; yourself! Item was changed: + ----- Method: HashedCollection>>union: (in category 'set logic') ----- - ----- Method: HashedCollection>>union: (in category 'enumerating') ----- union: aCollection "Answer the set theoretic union of the receiver and aCollection, using the receiver's notion of equality and not side effecting the receiver at all." ^ self copy addAll: aCollection; yourself ! From lewis at mail.msen.com Thu Mar 11 22:49:46 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Thu, 11 Mar 2021 17:49:46 -0500 Subject: [squeak-dev] The Inbox: Collections-dtl.931.mcz In-Reply-To: References: Message-ID: <20210311224946.GA91573@shell.msen.com> Every once in a while I find myself hunting around to locate the basic set operations. These should be simple and obvious so I think they deserve their own method category. I also added the trivial implementation of #symmetricDifference: because it seemed to be inexplicably missing. Most likely this would benefit from optimization, but the simple implementation is readable and actually looks symmetric, so it seems like a good start. OK to move to trunk? Dave On Thu, Mar 11, 2021 at 10:44:44PM +0000, commits at source.squeak.org wrote: > A new version of Collections was added to project The Inbox: > http://source.squeak.org/inbox/Collections-dtl.931.mcz > > ==================== Summary ==================== > > Name: Collections-dtl.931 > Author: dtl > Time: 11 March 2021, 5:44:43.577146 pm > UUID: 1ed239e3-d108-43c3-8b6e-de8c43d842d1 > Ancestors: Collections-nice.930 > > Set logic methods should be discoverable, so give them a method category. Add an implementation of Collection>>symmetricDifference: so that the basic set operations of union, intersection, difference, and symmetric difference are available. > > =============== Diff against Collections-nice.930 =============== > > Item was changed: > + ----- Method: Collection>>difference: (in category 'set logic') ----- > - ----- Method: Collection>>difference: (in category 'enumerating') ----- > difference: aCollection > "Answer the set theoretic difference of two collections." > > ^ self reject: [:each | aCollection includes: each]! > > Item was changed: > + ----- Method: Collection>>intersection: (in category 'set logic') ----- > - ----- Method: Collection>>intersection: (in category 'enumerating') ----- > intersection: aCollection > "Answer the set theoretic intersection of two collections." > > ^ self select: [:each | aCollection includes: each]! > > Item was added: > + ----- Method: Collection>>symmetricDifference: (in category 'set logic') ----- > + symmetricDifference: aCollection > + "Answer the set theoretic symmetric difference of two collections." > + > + ^ (self difference: aCollection) union: (aCollection difference: self) > + ! > > Item was changed: > + ----- Method: Collection>>union: (in category 'set logic') ----- > - ----- Method: Collection>>union: (in category 'enumerating') ----- > union: aCollection > "Answer the set theoretic union of two collections." > > ^ self asSet addAll: aCollection; yourself! > > Item was changed: > + ----- Method: HashedCollection>>union: (in category 'set logic') ----- > - ----- Method: HashedCollection>>union: (in category 'enumerating') ----- > union: aCollection > "Answer the set theoretic union of the receiver and aCollection, using the receiver's notion of equality and not side effecting the receiver at all." > > ^ self copy addAll: aCollection; yourself > > ! > > From nicolas.cellier.aka.nice at gmail.com Fri Mar 12 02:13:55 2021 From: nicolas.cellier.aka.nice at gmail.com (Nicolas Cellier) Date: Fri, 12 Mar 2021 03:13:55 +0100 Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> Message-ID: Great explanation and great findings! Le jeu. 11 mars 2021 à 19:52, Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> a écrit : > Thanks a lot for the collaboration, Marcel! :-) > > > > We basically figured out that the debugger that pops up from an > unhandled error (or warning) must never try debugging a simulated process > but always the "genuine process", which is the one that is actually running > and which may do the code simulation for another process. > > *A small summary of this bug* for all interested readers who are not > yet familiar with the debugging machinery: The actual issue causing all the > debugger chains was a mechanism called *process-faithful debugging.* In a > nutshell, it makes sure that when you * debug an expression such as > "Process activeProcess",* the expression answers the correct process > instance even when being debugged (that is, it must answer the *process **being > debugged* instead of the *debugger process* which is responsible for the > debugging). Process-faithful debugging works by *redirecting all sends to > ProcessorScheduler **>> **#activeProcess to a so-called #effectiveProcess* > *.* However, when some error occurred in the debugging process during > a debugging step (that is, *a simulation error* such as [1] [2] > occurred), a second debugger was opened - but because #activeProcess was > just being subjected to redirection, this second debugger did not interrupt > the *debugging process* but the *process being debugged* instead. As a > consequence, *the faulty debugging process kept running* and was given > the opportunity to do any other harm. If you now take a look into how > Object >> #at: or Object >> #doesNotUnderstand: are implemented (that > is, by *unlimited recursion*), you will see that *it could fire one > debugger after the next one* this way, without limitation, causing the > infinite debugger chains that broke your images. > > *The solution,* in its simplest form, was pretty straightforward: *When > opening a debugger from an error* (see StandardToolSet >> #handleError: > and others), make sure *not to honor process-faithful debugging* but > always open the debugger on the actually running process, which we decided > to call *genuineProcess* for sake of differentiation from #activeProcess. > The rest of the changeset focuses on some *additional refactoring of the > overall debugging API* on Process and ProcessorScheduler, striving to > make it more intuitive for application developers to choose the right > process and context for debugging. > > If you want to learn even more details, the first thread provided by > Marcel should be quite interesting (though also quite long). Otherwise, > we'll be here for your questions. :-) > > What an interesting project this has been! I'm already looking forward to > the next one! :-) > > Best, > Christoph > > [1] http://forum.world.st/The-Trunk-Kernel-ct-1357-mcz-td5124373.html > [2] > http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-nextPut-tp5108125.html > > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Taeumel, Marcel > *Gesendet:* Donnerstag, 11. März 2021 18:01:55 > *An:* squeak-dev > *Betreff:* [squeak-dev] Please try out | Fixes for debugger invocation > during code simulation > > Hi all! > > Christoph put in a lot of effort to figure out the cause of infinite > debugger chains under various circumstances. He is curious how far > "debugging the debugger" can work and how possible improvements to code > simulation might look like. > > We basically figured out that the debugger that pops up from an unhandled > error (or warning) must never try debugging a simulated process but always > the "genuine process", which is the one that is actually running and which > may do the code simulation for another process. > > Please find attached a change set with that fix. Tests are in > "DebuggerTests" and "ProcessTest". *The most interesting methods are > ProcessorScheduler >> #debugContext:title:full:contents: and Process >> > #debugWithTitle:full:contents:. *Please take a look at their comments. > > We will merge this into Trunk in a some days, given that there are no > objections. :-) > > Related discussions: > http://forum.world.st/I-broke-the-debugger-tp5110752p5110814.html > http://forum.world.st/The-Inbox-Morphic-ct-1610-mcz-tp5108228.html > > Best, > Marcel and Christoph > > P.S.: Debugging a dialog invocation looks nicer now. Try it out. > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 13738 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 13738 bytes Desc: not available URL: From marcel.taeumel at hpi.de Fri Mar 12 09:06:46 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 12 Mar 2021 10:06:46 +0100 Subject: [squeak-dev] The Inbox: Collections-dtl.931.mcz In-Reply-To: <20210311224946.GA91573@shell.msen.com> References: <20210311224946.GA91573@shell.msen.com> Message-ID: +1 !! :-) Thanks! Am 11.03.2021 23:49:54 schrieb David T. Lewis : Every once in a while I find myself hunting around to locate the basic set operations. These should be simple and obvious so I think they deserve their own method category. I also added the trivial implementation of #symmetricDifference: because it seemed to be inexplicably missing. Most likely this would benefit from optimization, but the simple implementation is readable and actually looks symmetric, so it seems like a good start. OK to move to trunk? Dave On Thu, Mar 11, 2021 at 10:44:44PM +0000, commits at source.squeak.org wrote: > A new version of Collections was added to project The Inbox: > http://source.squeak.org/inbox/Collections-dtl.931.mcz > > ==================== Summary ==================== > > Name: Collections-dtl.931 > Author: dtl > Time: 11 March 2021, 5:44:43.577146 pm > UUID: 1ed239e3-d108-43c3-8b6e-de8c43d842d1 > Ancestors: Collections-nice.930 > > Set logic methods should be discoverable, so give them a method category. Add an implementation of Collection>>symmetricDifference: so that the basic set operations of union, intersection, difference, and symmetric difference are available. > > =============== Diff against Collections-nice.930 =============== > > Item was changed: > + ----- Method: Collection>>difference: (in category 'set logic') ----- > - ----- Method: Collection>>difference: (in category 'enumerating') ----- > difference: aCollection > "Answer the set theoretic difference of two collections." > > ^ self reject: [:each | aCollection includes: each]! > > Item was changed: > + ----- Method: Collection>>intersection: (in category 'set logic') ----- > - ----- Method: Collection>>intersection: (in category 'enumerating') ----- > intersection: aCollection > "Answer the set theoretic intersection of two collections." > > ^ self select: [:each | aCollection includes: each]! > > Item was added: > + ----- Method: Collection>>symmetricDifference: (in category 'set logic') ----- > + symmetricDifference: aCollection > + "Answer the set theoretic symmetric difference of two collections." > + > + ^ (self difference: aCollection) union: (aCollection difference: self) > + ! > > Item was changed: > + ----- Method: Collection>>union: (in category 'set logic') ----- > - ----- Method: Collection>>union: (in category 'enumerating') ----- > union: aCollection > "Answer the set theoretic union of two collections." > > ^ self asSet addAll: aCollection; yourself! > > Item was changed: > + ----- Method: HashedCollection>>union: (in category 'set logic') ----- > - ----- Method: HashedCollection>>union: (in category 'enumerating') ----- > union: aCollection > "Answer the set theoretic union of the receiver and aCollection, using the receiver's notion of equality and not side effecting the receiver at all." > > ^ self copy addAll: aCollection; yourself > > ! > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 12 12:17:49 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 12 Mar 2021 12:17:49 0000 Subject: [squeak-dev] The Inbox: Tools-ct.1033.mcz Message-ID: A new version of Tools was added to project The Inbox: http://source.squeak.org/inbox/Tools-ct.1033.mcz ==================== Summary ==================== Name: Tools-ct.1033 Author: ct Time: 12 March 2021, 1:17:45.909559 pm UUID: 19163e49-2ba1-3148-981f-2e219da2c514 Ancestors: Tools-mt.1030 Fixes styling in change sorters if no real method is selected. No need to invoke Shout on messages such as "method was removed". Using an instance variable for this to avoid duplication of the contents logic. Reuploaded to fix #warnIverNotCopiedIn:sel: warning. Replaces Tools-ct.1031, which can be moved to the treated inbox. =============== Diff against Tools-mt.1030 =============== Item was changed: CodeHolder subclass: #ChangeSorter + instanceVariableNames: 'parent myChangeSet currentClassName currentSelector priorChangeSetList contentsAreStyleable' - instanceVariableNames: 'parent myChangeSet currentClassName currentSelector priorChangeSetList' classVariableNames: '' poolDictionaries: '' category: 'Tools-Changes'! + !ChangeSorter commentStamp: 'ct 3/10/2021 18:24' prior: 0! - !ChangeSorter commentStamp: 'wiz 2/3/2010 23:38' prior: 0! I display a ChangeSet. Two of me are in a DualChangeSorter. aStringOrNil Instance Variables currentClassName: currentSelector: myChangeSet: parent: priorChangeSetList: + contentsAreStyleable currentClassName - string parseable into class-name [class] [class trait] needs to be fitlered by (self withoutItemAnnotation: currentClassName) to remove pakaging note currentSelector - string parseable into selector-name needs to be fitlered by (self withoutItemAnnotation: currentSelector) to remove pakaging note myChangeSet - name of current changeset parent -the dual changesorter that contains this one. Used for dealing with the other half. priorChangeSetList + - holds the current change set list. Used to detect changes in list when a newly generated list no long match the prior list.! - - holds the current change set list. Used to detect changes in list when a newly generated list no long match the prior list. - ! Item was changed: ----- Method: ChangeSorter>>aboutToStyle: (in category 'code pane') ----- aboutToStyle: aStyler "This is a notification that aStyler is about to re-style its text. Set the classOrMetaClass in aStyler, so that identifiers will be resolved correctly. Answer true to allow styling to proceed, or false to veto the styling" + contentsAreStyleable ~= false ifFalse: [^false]. - self isModeStyleable ifFalse: [^false]. - self currentSelector ifNil: [^false]. aStyler classOrMetaClass: self selectedClassOrMetaClass. ^true! Item was changed: ----- Method: ChangeSorter>>setContents (in category 'code pane') ----- setContents "return the source code that shows in the bottom pane" | sel class strm changeType | self clearUserEditFlag. + contentsAreStyleable := false. myChangeSet ifNil: [^ contents := String empty]. "should not happen but can" currentClassName ifNil: [^ contents := myChangeSet preambleString ifNil: [String empty]]. class := self selectedClassOrMetaClass. (sel := self selectedMessageName) == nil ifFalse: [changeType := (myChangeSet atSelector: (sel := sel asSymbol) class: class). changeType == #remove ifTrue: [^ contents := 'Method has been removed (see versions)']. changeType == #addedThenRemoved ifTrue: [^ contents := 'Added then removed (see versions)']. class ifNil: [^ contents := 'Method was added, but cannot be found!!']. (class includesSelector: sel) ifFalse: [^ contents := 'Method was added, but cannot be found!!']. + contentsAreStyleable := true. contents := class sourceCodeAt: sel. (#(prettyPrint prettyDiffs) includes: contentsSymbol) ifTrue: [contents := class prettyPrinterClass format: contents in: class notifying: nil]. + self showingAnyKindOfDiffs ifTrue: [ + contentsAreStyleable := false. + contents := self diffFromPriorSourceFor: contents]. - self showingAnyKindOfDiffs - ifTrue: [contents := self diffFromPriorSourceFor: contents]. ^ contents := contents asText makeSelectorBoldIn: class] ifTrue: [strm := WriteStream on: (String new: 100). (myChangeSet classChangeAt: (self withoutItemAnnotation: currentClassName)) do: [:each | each = #remove ifTrue: [strm nextPutAll: 'Entire class was removed.'; cr]. each = #addedThenRemoved ifTrue: [strm nextPutAll: 'Class was added then removed.']. each = #rename ifTrue: [strm nextPutAll: 'Class name was changed.'; cr]. each = #add ifTrue: [strm nextPutAll: 'Class definition was added.'; cr]. each = #change ifTrue: [strm nextPutAll: 'Class definition was changed.'; cr]. each = #reorganize ifTrue: [strm nextPutAll: 'Class organization was changed.'; cr]. each = #comment ifTrue: [strm nextPutAll: 'New class comment.'; cr. ]]. ^ contents := strm contents].! Item was changed: ----- Method: ChangeSorter>>veryDeepInner: (in category 'creation') ----- veryDeepInner: deepCopier "Copy all of my instance variables. Some need to be not copied at all, but shared." super veryDeepInner: deepCopier. "parent := parent. Weakly copied" "myChangeSet := myChangeSet. Weakly copied" currentClassName := currentClassName veryDeepCopyWith: deepCopier. "currentSelector := currentSelector. Symbol" priorChangeSetList := priorChangeSetList veryDeepCopyWith: deepCopier. + "contentsAreStyleable := contentsAreStyleable. Cache"! - - - ! From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 12 12:59:48 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 12 Mar 2021 12:59:48 +0000 Subject: [squeak-dev] Lookup classes for context-relative doIts Message-ID: <411d2269b25843d7926bfa244b1586af@student.hpi.uni-potsdam.de> Hi all, recently, Patrick has raised an interesting question about doIt expression in debuggers/context-relative environments. Here is a concrete example: Foo subclass Bar subclass Baz Foo>>something ^ #foo Bar>>something ^ {super something. #bar} Baz>>something ^ {super something. #baz} "Baz new something" answers "#((foo bar) baz)" of course. Now debug the send and step into Baz(Bar)>>something so that the next send "super something" will answer "#foo". However, if you select the expression in the contents pane and print-it (you can also do the same in the ContextVariablesInspector on the right), you will get "#(foo bar)" instead. The reason is that the context-relative doIt will be compiled against the class of the context receiver - which is Baz - instead of the method class of the context. See Compiler >> #classForReceiver:context: and senders. Here is a very simple patch that could solve this problem: Compiler>>classForReceiver: receiver context: contextOrNil - ^thisContext objectClass: (contextOrNil ifNil: [receiver] ifNotNil: [contextOrNil receiver]) + contextOrNil ifNil: [^ thisContext objectClass: receiver]. + ^ contextOrNil method methodClass So I would like to discuss this behavior: In my opinion, it is definitively confusing that a print-it in a debugger pane behaves differently than actually sending the message. We cannot always reach exactly the same result and behavior, but IMHO we should always strive for it. On the other hand, especially when working in the ContextVariablesInspector instead of the contents pane, you might indeed expect that your doits are compiled against the actual receiver class. Another consequence of the above patch would be that instance variables defined in subclasses of the context methodClass become unavailable for doits. However, you can still use the left receiver inspector for reaching these variables. What do you think? :-) Would it be okay to use the lookup class of the selected context's method for context-relative doits or do you have any objections against it? Or do you think it is necessary to distinguish between the ContextVariablesInspector and the contents pane (while I think this would increase the perceived complexity, too ...)? Looking forward to your opinions - if you do not have any objections, I will send my patch to the inbox soon. :-) Best, Christoph PS1: Note that we would also need to patch Shout styling accordingly. However, this shouldn't be a huge problem. PS2: When talking about the "execution environment" of doit expressions (not to be confused with the Environment class for bindings!), we might also consider other aspects. Should we maybe also apply process-faithful debugging to them? Until today, stepping vs. doing-it an expression that refers to "Processor activeProcess" in a debugger yields different results ... -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 12 13:59:43 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 12 Mar 2021 13:59:43 0000 Subject: [squeak-dev] The Trunk: Collections-dtl.931.mcz Message-ID: David T. Lewis uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-dtl.931.mcz ==================== Summary ==================== Name: Collections-dtl.931 Author: dtl Time: 11 March 2021, 5:44:43.577146 pm UUID: 1ed239e3-d108-43c3-8b6e-de8c43d842d1 Ancestors: Collections-nice.930 Set logic methods should be discoverable, so give them a method category. Add an implementation of Collection>>symmetricDifference: so that the basic set operations of union, intersection, difference, and symmetric difference are available. =============== Diff against Collections-nice.930 =============== Item was changed: + ----- Method: Collection>>difference: (in category 'set logic') ----- - ----- Method: Collection>>difference: (in category 'enumerating') ----- difference: aCollection "Answer the set theoretic difference of two collections." ^ self reject: [:each | aCollection includes: each]! Item was changed: + ----- Method: Collection>>intersection: (in category 'set logic') ----- - ----- Method: Collection>>intersection: (in category 'enumerating') ----- intersection: aCollection "Answer the set theoretic intersection of two collections." ^ self select: [:each | aCollection includes: each]! Item was added: + ----- Method: Collection>>symmetricDifference: (in category 'set logic') ----- + symmetricDifference: aCollection + "Answer the set theoretic symmetric difference of two collections." + + ^ (self difference: aCollection) union: (aCollection difference: self) + ! Item was changed: + ----- Method: Collection>>union: (in category 'set logic') ----- - ----- Method: Collection>>union: (in category 'enumerating') ----- union: aCollection "Answer the set theoretic union of two collections." ^ self asSet addAll: aCollection; yourself! Item was changed: + ----- Method: HashedCollection>>union: (in category 'set logic') ----- - ----- Method: HashedCollection>>union: (in category 'enumerating') ----- union: aCollection "Answer the set theoretic union of the receiver and aCollection, using the receiver's notion of equality and not side effecting the receiver at all." ^ self copy addAll: aCollection; yourself ! From christoph.thiede at student.hpi.uni-potsdam.de Fri Mar 12 16:35:32 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Fri, 12 Mar 2021 10:35:32 -0600 (CST) Subject: [squeak-dev] Tackling Context>>#runUntilErrorReturnFrom: (was: BUG/REGRESSION while debugging Generator >> #nextPut:) In-Reply-To: References: <9ed2db8e40684297b83d98e311e76a4b@student.hpi.uni-potsdam.de> <25a67367ce4f4ee68d0509659cb10c72@student.hpi.uni-potsdam.de> <1615231296272-0.post@n4.nabble.com> Message-ID: <1615566932862-0.post@n4.nabble.com> By the way, another occurrence for this issue is when you debug such an expression: [^6*7] ensure: [2+3] Step through the first block, into Context>>aboutToReturn:through:, and then over #return:through:. I think the cause is the same. ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 12 18:26:25 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 12 Mar 2021 18:26:25 +0000 Subject: [squeak-dev] Merge Request: removeClass.cs In-Reply-To: References: <9c61ec35044a4b0abbcdc8b780abd47d@student.hpi.uni-potsdam.de> <, > <50a5273d783648e984dd1d91c8b52bfd@student.hpi.uni-potsdam.de>, Message-ID: Hi Marcel, with reference to the Win32 UX Guidelines, I was trying to express exactly the opposite: Simple, non-self-descriptive button labels can be dangerous because users often do not read the entire dialog before clicking the supposedly right button. For this reason, I think we should rather have a general shift towards more "wordy" buttons than towards more abstract button titles. :-) However, we could prepend every action with a short word, something like: [*Yes,* remove it] [*Yes,* remove it and browse references] [*Cancel*] [*Cancel* but browse references] I think the win32 guidelines are really interesting here. They also propose command links that can be used to explain the single options in greater detail - and also, they provide a modern look :-) -, so if we had some free resources, we could also build something similar for the MorphicUIManager. Iirc the guidelines also mention a pattern to put the Cancel button into a corner to separate it from the "main proceed actions". We could also apply this pattern. However, all of these ideas would be more complex than sticking with the current, limited possibilities ... What do you think? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 3. März 2021 12:17:27 An: squeak-dev Betreff: Re: [squeak-dev] Merge Request: removeClass.cs > Hm, but wouldn't this make the labels even longer and harder to read? Let me rephrase. The current labels are way too wordy. They should, however, start with a simple "Yes" or "No", followed by a compact explanation of what else happens when users click the button. Given that the title reads "Remove class", the buttons could be: [Yes] [Yes, and browse references] [No] [No, but browse references] Best, Marcel Am 03.03.2021 12:13:37 schrieb Thiede, Christoph : Hi Marcel, thanks for the feedback! > Could you keep the title Good catch! That functionality is not provided at the moment by UIManager>>#chooseFrom:.... We would need to extend the UIManager protocol first. Which I would actually dislike to do because it's finally time to implement a proper UserNotification hierarchy instead. I'm looking really forward to tackle this one soon! :-) > and add the prefixes "yes" or "no" before the options? Hm, but wouldn't this make the labels even longer and harder to read? Also, I intended to avoid generic yes/no labels as also recommended by the Win32 UX Guidelines [1], for example. Isn't it rather a good thing to force the user to think about the action they are going to select before they do the wrong thing by accident? (The same discussion could apply to the standard "Is it OK to discard" dialog. I have seen multiple Squeak newbies, including myself, that were remarkably confused by the semantics of this dialog. I would vote for redesigning this dialog, too, by the way. :-)) > What is your preferred way of having line breaks in the text? My preferred way would be to defer this job to the UIManager implementation (more concretely: DialogWindow), finally. It just feels wrong to hack this into every domain-specific notificator, and different font sizes/styles are not honored at all at the moment. Auto line-breaking could try to break the text into an approximately squared shape, similar to what Microsoft Windows and probably other window managers are doing. But this would require some trial- and failure or approximation logic in the UI implementation, I guess. > What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. Rather not, if possible. :-) I use the browse options very often (except the "sorry I asked" one) and it would be a shame to spend a second click for it. And reduce visibility. We could also make use of links inside the text, but this would be a downgrade as well since they do not support proper keyboard navigation. Also, clicking a link would not close the dialog automatically. What do you think? Are four buttons really too much? :-) Best, Christoph [1] https://docs.microsoft.com/en-us/windows/win32/uxguide/win-dialog-box#commit-buttons:~:text=Responding%20to%20main%20instructions ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 3. März 2021 10:18:52 An: squeak-dev Betreff: Re: [squeak-dev] Merge Request: removeClass.cs Hmm... tricky. :-) Here is the current one: [cid:6ab47abe-1e5c-494a-840d-b25a59cb71a5] - Could you keep the title and add the prefixes "yes" or "no" before the options? - What is your preferred way of having line breaks in the text? Here is the current remove-selector dialog: [cid:75ebde4b-b7dd-45dc-b2a6-15f70ec12617] ... Well, this does not scale at all. What about having a single extra button for "more options" in such confirmation dialogs? Maybe like a small drop-down menu. [Yes] [No] <--- SPACE---> [More...] Best, Marcel Am 02.03.2021 18:26:16 schrieb Thiede, Christoph : This changeset refactors the #removeClass logic (which has been upgraded by Marcel recently) and extracts it to SystemNavigation, analogously to System-ct.1221. It also refines the dialog to search for senders and subclasses of the class to remove as we know it from #removeMessage. [cid:21b5558d-d73d-4d2c-bcc4-eeb40f7dee49] Please merge or give me feedback for improvements. :-) Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 28990 bytes Desc: image.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 20780 bytes Desc: image.png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: pastedImage.png Type: image/png Size: 23381 bytes Desc: pastedImage.png URL: From vanessa at codefrau.net Fri Mar 12 22:26:00 2021 From: vanessa at codefrau.net (Vanessa Freudenberg) Date: Fri, 12 Mar 2021 14:26:00 -0800 Subject: [squeak-dev] Lookup classes for context-relative doIts In-Reply-To: <411d2269b25843d7926bfa244b1586af@student.hpi.uni-potsdam.de> References: <411d2269b25843d7926bfa244b1586af@student.hpi.uni-potsdam.de> Message-ID: On Fri, Mar 12, 2021 at 5:00 AM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Would it be okay to use the lookup class of the selected context's method > for context-relative doits > Sounds like a good idea to me. - Vanessa - -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Sat Mar 13 14:57:48 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sat, 13 Mar 2021 09:57:48 -0500 Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> Message-ID: <20210313145748.GA75627@shell.msen.com> +1 Thank you for doing this and for explaining the issues so well. Dave On Fri, Mar 12, 2021 at 03:13:55AM +0100, Nicolas Cellier wrote: > Great explanation and great findings! > > > Le jeu. 11 mars 2021 ?? 19:52, Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> a ??crit : > > > Thanks a lot for the collaboration, Marcel! :-) > > > > > > > We basically figured out that the debugger that pops up from an > > unhandled error (or warning) must never try debugging a simulated process > > but always the "genuine process", which is the one that is actually running > > and which may do the code simulation for another process. > > > > *A small summary of this bug* for all interested readers who are not > > yet familiar with the debugging machinery: The actual issue causing all the > > debugger chains was a mechanism called *process-faithful debugging.* In a > > nutshell, it makes sure that when you * debug an expression such as > > "Process activeProcess",* the expression answers the correct process > > instance even when being debugged (that is, it must answer the *process **being > > debugged* instead of the *debugger process* which is responsible for the > > debugging). Process-faithful debugging works by *redirecting all sends to > > ProcessorScheduler **>> **#activeProcess to a so-called #effectiveProcess* > > *.* However, when some error occurred in the debugging process during > > a debugging step (that is, *a simulation error* such as [1] [2] > > occurred), a second debugger was opened - but because #activeProcess was > > just being subjected to redirection, this second debugger did not interrupt > > the *debugging process* but the *process being debugged* instead. As a > > consequence, *the faulty debugging process kept running* and was given > > the opportunity to do any other harm. If you now take a look into how > > Object >> #at: or Object >> #doesNotUnderstand: are implemented (that > > is, by *unlimited recursion*), you will see that *it could fire one > > debugger after the next one* this way, without limitation, causing the > > infinite debugger chains that broke your images. > > > > *The solution,* in its simplest form, was pretty straightforward: *When > > opening a debugger from an error* (see StandardToolSet >> #handleError: > > and others), make sure *not to honor process-faithful debugging* but > > always open the debugger on the actually running process, which we decided > > to call *genuineProcess* for sake of differentiation from #activeProcess. > > The rest of the changeset focuses on some *additional refactoring of the > > overall debugging API* on Process and ProcessorScheduler, striving to > > make it more intuitive for application developers to choose the right > > process and context for debugging. > > > > If you want to learn even more details, the first thread provided by > > Marcel should be quite interesting (though also quite long). Otherwise, > > we'll be here for your questions. :-) > > > > What an interesting project this has been! I'm already looking forward to > > the next one! :-) > > > > Best, > > Christoph > > > > [1] http://forum.world.st/The-Trunk-Kernel-ct-1357-mcz-td5124373.html > > [2] > > http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-nextPut-tp5108125.html > > > > ------------------------------ > > *Von:* Squeak-dev im > > Auftrag von Taeumel, Marcel > > *Gesendet:* Donnerstag, 11. M??rz 2021 18:01:55 > > *An:* squeak-dev > > *Betreff:* [squeak-dev] Please try out | Fixes for debugger invocation > > during code simulation > > > > Hi all! > > > > Christoph put in a lot of effort to figure out the cause of infinite > > debugger chains under various circumstances. He is curious how far > > "debugging the debugger" can work and how possible improvements to code > > simulation might look like. > > > > We basically figured out that the debugger that pops up from an unhandled > > error (or warning) must never try debugging a simulated process but always > > the "genuine process", which is the one that is actually running and which > > may do the code simulation for another process. > > > > Please find attached a change set with that fix. Tests are in > > "DebuggerTests" and "ProcessTest". *The most interesting methods are > > ProcessorScheduler >> #debugContext:title:full:contents: and Process >> > > #debugWithTitle:full:contents:. *Please take a look at their comments. > > > > We will merge this into Trunk in a some days, given that there are no > > objections. :-) > > > > Related discussions: > > http://forum.world.st/I-broke-the-debugger-tp5110752p5110814.html > > http://forum.world.st/The-Inbox-Morphic-ct-1610-mcz-tp5108228.html > > > > Best, > > Marcel and Christoph > > > > P.S.: Debugging a dialog invocation looks nicer now. Try it out. > > > > > > > From m at jaromir.net Sat Mar 13 16:43:34 2021 From: m at jaromir.net (Jaromir Matas) Date: Sat, 13 Mar 2021 10:43:34 -0600 (CST) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615455553312-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615372211711-0.post@n4.nabble.com> <1615455553312-0.post@n4.nabble.com> Message-ID: <1615653814108-0.post@n4.nabble.com> Hi Christoph and all, What is the expected semantics of the Debugger's Abandon? To quit and do nothing more to the debugged process or continue unwinding? I thought the former was right but the Debugger does the latter. Is it really necessary to run all unwinds when closing the abandoned Debugger window? Because that is the cause of the Unwind errors... Normally, when hitting Abandon, the debugged process terminates and the current UI continues. But if there are unfinished unwinds in the debugged process and we hit Abandon, the control jumps from the UI process to the debugged one (as Christoph described) and stays there as an active UI process which creates an impossible situation where we have: - an active process being the former debugged one which is not the real active one but only referred to as an effective process - the real active process (genuine process) is the UI process previously controlling the debugging with the effective process variable set - this real active process is even erroneously answering true to #isTerminated (because it's not 'active' and its suspendedContext is nil) - and this real active process will eventually become the active UI again... - and all this further leads to two simultaneous UI processes alternating control... and more... a nightmare ;) Check the enclosed printscreen... Long story short if I'm not wrong and the Debugger shouldn't do all the unwinds when Abandoned, then the fix is a oneliner: (Instead of termintating the debugged process via #terminate which runs the unwinds, let's just 'make it' terminated) Debugger >> windowIsClosing "My window is being closed; clean up. Restart the low space watcher." interruptedProcess == nil ifTrue: [^ self]. >>> "Now terminate the interruptedProcess but without unwinds!" >>> interruptedProcess suspendedContext terminate. interruptedProcess := nil. contextStack := nil. receiverInspector := nil. contextVariablesInspector := nil. Smalltalk installLowSpaceWatcher. "restart low space handler" Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From leves at caesar.elte.hu Sat Mar 13 19:44:41 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Sat, 13 Mar 2021 20:44:41 +0100 (CET) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615653814108-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615372211711-0.post@n4.nabble.com> <1615455553312-0.post@n4.nabble.com> <1615653814108-0.post@n4.nabble.com> Message-ID: Hi Jaromir, If we just terminated the process as you suggested without doing proper unwinding, resource management would become impossible and there would be leaked resources (files, sockets, etc) everywhere. Levente On Sat, 13 Mar 2021, Jaromir Matas wrote: > Hi Christoph and all, > > What is the expected semantics of the Debugger's Abandon? To quit and do > nothing more to the debugged process or continue unwinding? > > I thought the former was right but the Debugger does the latter. Is it > really necessary to run all unwinds when closing the abandoned Debugger > window? > > Because that is the cause of the Unwind errors... Normally, when hitting > Abandon, the debugged process terminates and the current UI continues. > > But if there are unfinished unwinds in the debugged process and we hit > Abandon, the control jumps from the UI process to the debugged one (as > Christoph described) and stays there as an active UI process which creates > an impossible situation where we have: > > - an active process being the former debugged one which is not the real > active one but only referred to as an effective process > - the real active process (genuine process) is the UI process previously > controlling the debugging with the effective process variable set > - this real active process is even erroneously answering true to > #isTerminated (because it's not 'active' and its suspendedContext is nil) > - and this real active process will eventually become the active UI again... > - and all this further leads to two simultaneous UI processes alternating > control... and more... a nightmare ;) > > Check the enclosed printscreen... > > > Long story short if I'm not wrong and the Debugger shouldn't do all the > unwinds when Abandoned, then the fix is a oneliner: > (Instead of termintating the debugged process via #terminate which runs the > unwinds, let's just 'make it' terminated) > > Debugger >> windowIsClosing > "My window is being closed; clean up. Restart the low space watcher." > > interruptedProcess == nil ifTrue: [^ self]. >>>> "Now terminate the interruptedProcess but without unwinds!" >>>> interruptedProcess suspendedContext terminate. > interruptedProcess := nil. > > contextStack := nil. > receiverInspector := nil. > contextVariablesInspector := nil. > Smalltalk installLowSpaceWatcher. "restart low space handler" > > > Thanks, > > > > ----- > ^[^ Jaromir > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Sat Mar 13 20:26:17 2021 From: m at jaromir.net (Jaromir Matas) Date: Sat, 13 Mar 2021 14:26:17 -0600 (CST) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615372211711-0.post@n4.nabble.com> <1615455553312-0.post@n4.nabble.com> <1615653814108-0.post@n4.nabble.com> Message-ID: <1615667177574-0.post@n4.nabble.com> Hi Levente, Thanks a lot for clarifying my confusion, my bad ;) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Sat Mar 13 20:30:09 2021 From: m at jaromir.net (Jaromir Matas) Date: Sat, 13 Mar 2021 14:30:09 -0600 (CST) Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> Message-ID: <1615667409182-0.post@n4.nabble.com> Hi Marcel, Christoph, trying to follow this wonderful job, thanks indeed :) A question: How is the genuine process supposed to answer #isTerminated, isActive etc.? At the moment it answers true to isTerminated if the effective process variable is set. As a consequence the genuine process is not shown on the Process Browser in such a case. The effective process rightly answers true to isActiveProcess but what about the genuine one? Generally there's not much difference between a genuine and a terminated process. Both have suspendedContext = nil. I guess the only difference is that the genuine process is not terminated, and Processor is the place keeping this information. Should there be two active processes? The genuine and the effective? And extend the isActiveProcess like self == Processor activeProcess or: [self effectiveProcess == Processor activeProcess] Thanks again, I hope I'm not confused again :) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Sun Mar 14 07:44:18 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 14 Mar 2021 01:44:18 -0600 (CST) Subject: [squeak-dev] The Inbox: Kernel-jar.1380.mcz In-Reply-To: <1615113726960-0.post@n4.nabble.com> References: <1615113726960-0.post@n4.nabble.com> Message-ID: <1615707858716-0.post@n4.nabble.com> Please remove this file from The Inbox, I'll repost this as a fileOut, sorry for the noise. ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Sun Mar 14 07:58:11 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 14 Mar 2021 01:58:11 -0600 (CST) Subject: [squeak-dev] Refactoring #terminate to get rid of 'cannot return' errors etc. Message-ID: <1615708691721-0.post@n4.nabble.com> This is a follow up on the following threads: [1] http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html#a5127336 [2] http://forum.world.st/The-Inbox-Kernel-jar-1377-mcz-td5127438.html#a5127439 I've noticed resuming a terminated process ends up with "cannot return" and similar errors. I'd like to offer an alternative approach requiring just a few tiny changes: A process is terminated when it suspends itself or some other process does. When someone resumes a terminated process it continues and eventually fails. I'd like to propose a terminal method where all processes terminate: Process>> terminated "When I reach this method, I'm terminated. Suspending or terminating me is harmless." thisContext terminateTo: nil. "sets thisContext sender to nil" self suspend. ^thisContext restart This approach would simplify the #isTerminated method and would require just two little tweaks in the #terminate method: terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. "Now all work is done and the process can terminate" >>>> ^self terminated]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: [self debug: ctxt title: 'Unwind error during termination']. "Set the receiver's context to Process>>#terminated for the benefit of isTerminated." >>>> ctxt setSender: nil receiver: self method: (Process>>#terminated) arguments: {} ] When the active process terminates itself it sends itself the #terminated message parking itself in a "deathtrap". When a process is being terminated by another process its bottom context set to #terminated, effectively parking it in the same trap again. That's it. Now the terminated process may get resumed or terminated again with no error. Now, while we're at it we could take care of the processes that terminate "naturally" by reaching the end of their defining block. We need to refactor #newProcess to create the terminal bottom context (the trap) and set it as the initial sender of a newly created process for a block. If the process finishes without explicit termination or via an exception it'll automatically park itself in the #terminated facility: newProcess "Answer a Process running the code in the receiver. The process is not scheduled. Create a new bottom context for Process>>#terminated and make it the sender of the new process for the benefit of Process>>#isTerminated." | newProcess bottomContext | "" "Simulation guard" newProcess := Process new. bottomContext := Context sender: nil receiver: newProcess method: (Process>>#terminated) arguments: {}. newProcess suspendedContext: (self asContextWithSender: bottomContext). newProcess priority: Processor activePriority. ^newProcess The previously used #forContext:priority: had to be inlined because of the cross reference - the new bottom context refers to the new process and the new process refers back to the new bottom context. So at this point all "normal" processes (i.e. those created via newProcess) will terminate in #terminated regardless of whether they terminated themselves, were terminated by another party or just reached their closing square bracket. There's a group of potentially weird processes created via forContext:priority: that can choose their own fate and won't in general follow the above logic. For these cases I left the final condition in #isTerminate: they are also considered terminated when they reach their last instruction (and stay there): isTerminated "Answer if the receiver is terminated, or at least terminating, i.e. if one of the following conditions is met: (1) the receiver is a defunct process (suspendedContext = nil or pc = nil) (2) the receiver is suspended within Process>>terminated, i.e. terminated (3) the suspendedContext is the bottomContext and the pc is at the endPC" self isActiveProcess ifTrue: [^false]. ^suspendedContext isNil or: [suspendedContext isDead] or: [suspendedContext methodClass == Process and: [suspendedContext selector == #terminated]] >>> or: [suspendedContext isBottomContext and: [suspendedContext atEnd]] Examples of such processes: p := Process forContext: [Processor activeProcess suspend] asContext priority: Processor activePriority +1. p resume Process forContext: [] asContext priority: 40 All tests are green but I'm aware this is just an idea that would have to be tested thoroughly against the VM and the debugger. Do you think this is something worth implementing though? For me, the code is more readable, process termination more orderly, no need for checking whether a process is terminated to avoid "cannot return" errors, the terminated processes are easily trackable and identifiable while debugging etc. I'm enclosing a changeset with the proposed changes: Refactor_#terminate.cs Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Sun Mar 14 13:30:04 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Sun, 14 Mar 2021 14:30:04 +0100 Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: <1615667409182-0.post@n4.nabble.com> References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> <1615667409182-0.post@n4.nabble.com> Message-ID: Hi Jaromir. > How is the genuine process supposed to answer #isTerminated, isActive etc.? So, you are wondering about the result of "genuineProcess isTerminated" being sent from a simulated process? Since it is an instance variable, this construction would not easily be possible. Meaning, it is not intended to access the genuine process from outside "Processor". > Should there be two active processes? The genuine and the effective? Well, at best, code simulation would be oblivious to the objects involved. So, that question would not arise. Yet, thinking about nested code simulation, one might argue that n processes are "active". :-) From a general perspective, however, only 1 process is running at a time. And most of that time, I would argue, it is some process being the genuine process, not an effective one. ;-)  > As a consequence the genuine process is not shown on the Process Browser in such a case. [... ] And extend the isActiveProcess like [...] No further changes to Process >> #isActiveProcess are needed for our current understanding of code simulation. :-) Given that debugging the debugger is tricky, debugging a process browser belongs to a similar category. Best, Marcel Am 13.03.2021 21:30:15 schrieb Jaromir Matas : Hi Marcel, Christoph, trying to follow this wonderful job, thanks indeed :) A question: How is the genuine process supposed to answer #isTerminated, isActive etc.? At the moment it answers true to isTerminated if the effective process variable is set. As a consequence the genuine process is not shown on the Process Browser in such a case. The effective process rightly answers true to isActiveProcess but what about the genuine one? Generally there's not much difference between a genuine and a terminated process. Both have suspendedContext = nil. I guess the only difference is that the genuine process is not terminated, and Processor is the place keeping this information. Should there be two active processes? The genuine and the effective? And extend the isActiveProcess like self == Processor activeProcess or: [self effectiveProcess == Processor activeProcess] Thanks again, I hope I'm not confused again :) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Sun Mar 14 15:48:01 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sun, 14 Mar 2021 15:48:01 +0000 Subject: [squeak-dev] #testBecomeForward fails when simulated in a rush Message-ID: <5f2b013b71ac40009143e860a3fd7769@student.hpi.uni-potsdam.de> Hi all, it's Sunday afternoon (at least in my timezone :D) and here's an interesting weekend issue for you, maybe even a bug in the VM: p := [ObjectTest new testBecomeForward] newProcess. p runUntil: [:c | c isDead]. In my fresh trunk image, this expression always fails, i.e. a TestFailure is raised from the second assertion in the test, pt3 == pt2. However, when running the test normally, i.e. executing the first block without simulation, the test passes as expected. Also, when I try to debug the simulation, the test passes again. But I even inserted a halt around the (pt3 == pt2) and could see that it actually evaluated to false. And when I change the expression like this, it suddenly passes: p := [ObjectTest new testBecomeForward] newProcess. p runUntil: [:c | Smalltalk garbageCollect. c isDead]. What is this? Does the VM require some kind of memory sweep before the object identity consistency is restored again? To me, this looks pretty suspicious at least. In SqueakJS, I cannot reproduce the issue, i.e., since https://github.com/codefrau/SqueakJS/pull/117, #testBecomeForward never fails. Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Sun Mar 14 18:16:59 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sun, 14 Mar 2021 18:16:59 0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1381.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1381.mcz ==================== Summary ==================== Name: Kernel-ct.1381 Author: ct Time: 14 March 2021, 7:16:55.476382 pm UUID: e555dad1-89ad-4143-b0b1-faa06c9044cb Ancestors: Kernel-mt.1380 Proposal: Revises usage and handling of primitive 19, also known as the simulation guard. Don't use it in #newProcess and variants since they don't involve any actual control logic. Instead, also show a simulation warning when debugging a control primitive (primitiveSignal primitiveWait primitiveResume primitiveSuspend). Improves integration of simulation guard warnings by signaling a Warning on the simulator stack rather than spawning a debugger on the debugged process. This also makes it easier to handle these warnings in a non-interactive context. See http://forum.world.st/Simulation-guard-lt-primitive-19-gt-crashes-the-image-td5127443.html and http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html for more information. =============== Diff against Kernel-mt.1380 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ + [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] + ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. + - primitiveIndex = 19 ifTrue: - [Processor activeProcess - debug: self - title:'Code simulation error' - full: false]. - ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: ["Transcript cr; nextPutAll: 'Processor activeProcess '; nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); nextPutAll: ' owner'; flush." value := primitiveIndex = 186 ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! From christoph.thiede at student.hpi.uni-potsdam.de Sun Mar 14 18:20:10 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Sun, 14 Mar 2021 13:20:10 -0500 (CDT) Subject: [squeak-dev] Simulation guard crashes the image In-Reply-To: <6E9AAE65-EB47-4BF7-8BCC-01BB6924B1DE@gmail.com> References: <1614848593348-0.post@n4.nabble.com> <7906b282ca044bf3b907ac9c9ee4c2da@student.hpi.uni-potsdam.de> <6E9AAE65-EB47-4BF7-8BCC-01BB6924B1DE@gmail.com> Message-ID: <1615746010321-0.post@n4.nabble.com> Hi Eliot, I have just uploaded Kernel-ct.1381 to the inbox. Please let me know how you think about it. :-) IMHO, the priority of the instantiated process should not be a problem because #newProcess and variants always use Processor activeProcess for reference. Rather, we might have a problem when a direct send to Process class >> #forContext:priority: is simulated where we do not have any simulation guard installed. But I think by simply showing a warning every time an attempt is made to resume/suspend a process (as done in Kernel-ct.1381), we should have fixed this problem, too. Have a nice weekend! Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From christoph.thiede at student.hpi.uni-potsdam.de Sun Mar 14 19:00:33 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Sun, 14 Mar 2021 14:00:33 -0500 (CDT) Subject: [squeak-dev] The Trunk: Morphic-eem.1735.mcz In-Reply-To: References: Message-ID: <1615748433871-0.post@n4.nabble.com> I like this change, too. How will we call the new buttons then? greenButton and purpleButton? :-) Eliot, could you maybe the next time insert a break or however it is called in the update stream before you push changes that depend on other versions? When I try to merge the changes from the previous week into my image, it freezes unrecoverably because the updater identifies a merge conflict for Morphic (no real problem, just some usual conflicts) and asks me to resolve it before #numEvents is installed - but the new Kernel versions were already loaded and depend on #numEvents ... I can solve this problem by compiling #numEvents manually, but it is a bit tedious to lose the latest state of my image and need to fix it manually, thus the notice. :-) Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Sun Mar 14 21:49:36 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 14 Mar 2021 16:49:36 -0500 (CDT) Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> <1615667409182-0.post@n4.nabble.com> Message-ID: <1615758576373-0.post@n4.nabble.com> Hi Marcel, > So, you are wondering about the result of "genuineProcess isTerminated" > being sent from a simulated process? No, I'm talking about a real situation while debugging e.g. the Christoph's example: 1. open Process Browser 2. open an explorer window on the UI process 3. do-it [self error: 'e1'] ensure: [^2] 4. now the UI process has become the debugged process and a new UI has been spawned 5. open an explorer window on the new UI process 6. hit Abandon on the debugger window and see what happened on the enclosed printscreen: - the original UI process became the UI process again but because of the bug Christoph has reported this original UI process is now still the effective process and the genuine process is still running and responding true to self #isTerminated e.g. in the explorer window etc. This causes the genuine process to disappear from the Process Browser window which I find very inconvenient and most likely wrong - well, we're no longer debugging yet the genuine process is not showing which makes it more difficult to realize what happened. This is why I ask whether the genuine process shouldn't be considered something but terminated :) Process Browser filters terminated processes out. > From a general perspective, however, only 1 process is running at a time. > And most of that time, I would argue, it is some process being the genuine > process, not an effective one. ;-)  I guess, however with simulation and jumps this may become a bit blurred... I've got to think about it. BTW, if you repeat step 3 will get you to the Unwind error and if you hit Proceed you end up with the two UI processes alternating every worldCycle, now of course both without the effective variable set and both again visible in the Process Browser. The only point I'm making is there are real pathological situations where you might want to see the genuine process while another process acts as the active process and considering it terminated is very confusing. Thanks and best regards, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Sun Mar 14 21:55:03 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sun, 14 Mar 2021 21:55:03 0000 Subject: [squeak-dev] The Trunk: EToys-eem.432.mcz Message-ID: Eliot Miranda uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-eem.432.mcz ==================== Summary ==================== Name: EToys-eem.432 Author: eem Time: 14 March 2021, 2:54:59.084913 pm UUID: 3c860a71-8994-4ff8-b978-93ea09ab6e0b Ancestors: EToys-nice.431 Add CameraInterface class>>cameraDevices to accompany SoundPlayer class>>playerDevices and SoundRecorder class>>recorderDevices. =============== Diff against EToys-nice.431 =============== Item was added: + ----- Method: CameraInterface class>>cameraDevices (in category 'utilities') ----- + cameraDevices + "CameraInterface cameraDevices" + ^Array streamContents: + [:s| | i | + i := 1. + [(self cameraName: i) + ifNotNil: [:cameraName| s nextPut: cameraName. true] + ifNil: [false]] whileTrue: [i := i + 1]]! From m at jaromir.net Sun Mar 14 23:21:44 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 14 Mar 2021 18:21:44 -0500 (CDT) Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: <1615758576373-0.post@n4.nabble.com> References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> <1615667409182-0.post@n4.nabble.com> <1615758576373-0.post@n4.nabble.com> Message-ID: <1615764104533-0.post@n4.nabble.com> Marcel, Christoph, one more question if I may: which of the two UI processes described in steps 1-6 is actually really running/VM executing their code? I'm unable to figure out... The genuine one reported as terminated or the active one but being only effective? Please, your help will be much appreciated. Many Thanks, J ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Mon Mar 15 08:35:06 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 15 Mar 2021 03:35:06 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> Message-ID: <1615797306053-0.post@n4.nabble.com> > Hi Jaromir, > thanks a lot for your answer! Great to hear that you have found some other > examples that would benefit > from my patch as well. :-) Hi Christoph, I've realized there's one disadvantage to your patch. It quite successfully masks the real issue but every occurrence/application of the patch leaves one suspended process behind - the one that was left prematurely through the non-local return - see the enclosed printscreen after two iterations of your example: Purple highligted processes are being left behind every occurrence of the patch application. The other problem I raised in http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-tp5127684p5127748.html is that the really executing process (which really is the genuine process) is invisible to the user because it responds true to isTerminated! In order to make this process visible I tweaked a bit the isTerminated as you can see at the top of the printscreen. The scary part is after one occurrence of the issue the image may happily run with the invisible UI forever - or to be precise until another error occurs and the invisible becomes visible :) Best, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Mon Mar 15 09:50:19 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 15 Mar 2021 10:50:19 +0100 Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615797306053-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> Message-ID: Hi Jaromir, > The other problem I raised in [...] > is that the really executing process (which really is the genuine process) > is invisible to the user because it responds true to isTerminated! In order > to make this process visible I tweaked a bit the isTerminated as you can see > at the top of the printscreen. In this discussion, you should always specify whether "responds to" involves a sender within a simulated or genuine "context". ;-) I am still not convinced that this is an actual problem. Best, Marcel Am 15.03.2021 09:35:15 schrieb Jaromir Matas : > Hi Jaromir, > thanks a lot for your answer! Great to hear that you have found some other > examples that would benefit > from my patch as well. :-) Hi Christoph, I've realized there's one disadvantage to your patch. It quite successfully masks the real issue but every occurrence/application of the patch leaves one suspended process behind - the one that was left prematurely through the non-local return - see the enclosed printscreen after two iterations of your example: Purple highligted processes are being left behind every occurrence of the patch application. The other problem I raised in http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-tp5127684p5127748.html is that the really executing process (which really is the genuine process) is invisible to the user because it responds true to isTerminated! In order to make this process visible I tweaked a bit the isTerminated as you can see at the top of the printscreen. The scary part is after one occurrence of the issue the image may happily run with the invisible UI forever - or to be precise until another error occurs and the invisible becomes visible :) Best, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Mon Mar 15 09:55:12 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 15 Mar 2021 10:55:12 +0100 Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: <1615764104533-0.post@n4.nabble.com> References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> <1615667409182-0.post@n4.nabble.com> <1615758576373-0.post@n4.nabble.com> <1615764104533-0.post@n4.nabble.com> Message-ID: Hi Jaromir, > The only point I'm making is there are real pathological situations where > you might want to see the genuine process while another process acts as the > active process and considering it terminated is very confusing. So, you see no problems in merging this change into Trunk? (For new discussions, you can always open up a new thread on the mailing list.) Best, Marcel Am 15.03.2021 00:21:52 schrieb Jaromir Matas : Marcel, Christoph, one more question if I may: which of the two UI processes described in steps 1-6 is actually really running/VM executing their code? I'm unable to figure out... The genuine one reported as terminated or the active one but being only effective? Please, your help will be much appreciated. Many Thanks, J ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Mon Mar 15 10:19:06 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:19:06 0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1381.mcz Message-ID: Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1381.mcz ==================== Summary ==================== Name: Kernel-mt.1381 Author: mt Time: 15 March 2021, 11:19:02.546586 am UUID: 11976771-8ccb-e941-83da-2ae26c3a9f55 Ancestors: Kernel-mt.1380 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against Kernel-mt.1380 =============== Item was changed: (PackageInfo named: 'Kernel') preamble: '"below, add code to be run before the loading of this package" + ProcessorScheduler instVarNames at: 2 put: ''genuineProcess''.'! - BlockClosure instVarNames at: 2 put: ''startpcOrMethod'''! Item was changed: ----- Method: Context>>cannotReturn: (in category 'private-exceptions') ----- cannotReturn: result + closureOrNil ifNotNil: [^ self cannotReturn: result to: self home sender]. + Processor debugWithTitle: 'Computation has been terminated!!' translated full: false.! - closureOrNil notNil ifTrue: - [^self cannotReturn: result to: self home sender]. - Processor activeProcess - debug: thisContext - title: 'computation has been terminated' - full: false.! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + primitiveIndex = 19 ifTrue: [ + [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] + ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. + - primitiveIndex = 19 ifTrue: - [Processor activeProcess - debug: self - title:'Code simulation error' - full: false]. - ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + [| effective | + effective := Processor activeProcess effectiveProcess. + "active == effective" + value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. - ["Transcript - cr; - nextPutAll: 'Processor activeProcess '; - nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); - nextPutAll: ' owner'; - flush." - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! Item was changed: ----- Method: ObjectTracer>>doesNotUnderstand: (in category 'very few messages') ----- doesNotUnderstand: aMessage + "Present a debugger before proceeding to re-send the message. All external messages (those not caused by the re-send) get trapped here." - "Present a debugger before proceeding to re-send the message" + self flag: #workaround. "ct: After the selection of buttons in the debugger has been refactored, return to a simple Warning here. See: http://forum.world.st/The-Trunk-Kernel-mt-1303-mcz-tp5112200p5112211.html" + Processor + debugWithTitle: ('Object Tracer ({1})' translated format: {self identityHash}) - "All external messages (those not caused by the re-send) get trapped here" - Processor activeProcess - debugWithTitle: 'Object Tracer (', self identityHash, ')' full: false contents: ('On an instance of\ {1} ({2})\\About to perform\ {3}\\Using the following arguments\ {4}' translated withCRs format: { thisContext objectClass: tracedObject. tracedObject identityHash. aMessage selector storeString. aMessage arguments printString}). + - ^ aMessage sendTo: tracedObject! Item was changed: ----- Method: Process>>evaluate:onBehalfOf: (in category 'private') ----- evaluate: aBlock onBehalfOf: aProcess + "Evaluate aBlock setting effectiveProcess to aProcess. Used in the execution simulation machinery to ensure that Processor activeProcess evaluates correctly when debugging, which is also known as process-faithful debugging." + + | oldEffectiveProcess | + aProcess == self ifTrue: [^ aBlock value]. "Optimization" + + oldEffectiveProcess := effectiveProcess. - "Evaluate aBlock setting effectiveProcess to aProcess, and all other variables other than - the scheduling ones to those of aProcess. Used in the execution simulation machinery - to ensure that Processor activeProcess evaluates correctly when debugging." - | range savedVariables | - "range accesses everything after myList, e.g. threadId, effectiveProcess, name, island, env" - range := 5 to: Process instSize. - savedVariables := range collect: [:i| self instVarAt: i]. - range do: - [:i| self instVarAt: i put: (aProcess instVarAt: i)]. effectiveProcess := aProcess. + ^ aBlock ensure: [effectiveProcess := oldEffectiveProcess]! - ^aBlock ensure: - ["write back any assigned-to variables." - range do: - [:i| | v | - ((v := self instVarAt: i) ~~ (aProcess instVarAt: i) - and: [v notNil]) ifTrue: - [aProcess instVarAt: i put: v]]. - "restore old values" - range with: savedVariables do: - [:i :var| self instVarAt: i put: var]]! Item was changed: ----- Method: Process>>terminate (in category 'changing process state') ----- terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. thisContext terminateTo: nil. self suspend. "If the process is resumed this will provoke a cannotReturn: error. Would self debug: thisContext title: 'Resuming a terminated process' be better?" ^self]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: + [self debugWithTitle: 'Unwind error during termination' translated full: false]. - [self debug: ctxt title: 'Unwind error during termination']. "Set the context to its endPC for the benefit of isTerminated." ctxt pc: ctxt endPC]! Item was changed: Object subclass: #ProcessorScheduler + instanceVariableNames: 'quiescentProcessLists genuineProcess' - instanceVariableNames: 'quiescentProcessLists activeProcess' classVariableNames: 'BackgroundProcess HighIOPriority LowIOPriority SystemBackgroundPriority SystemRockBottomPriority TimingPriority UserBackgroundPriority UserInterruptPriority UserSchedulingPriority' poolDictionaries: '' category: 'Kernel-Processes'! !ProcessorScheduler commentStamp: '' prior: 0! My single instance, named Processor, coordinates the use of the physical processor by all Processes requiring service.! Item was changed: ----- Method: ProcessorScheduler>>activePriority (in category 'accessing') ----- activePriority "Answer the priority level of the currently running Process." + ^ self activeProcess priority! - ^activeProcess effectiveProcess priority! Item was changed: ----- Method: ProcessorScheduler>>activeProcess (in category 'accessing') ----- activeProcess + "Answer the active process (from the user's perspective), which can be simulated by the genuinely running process (from the system's perspective). See Process >> #evaluate:onBehalfOf:." - "Answer the currently running Process." + ^genuineProcess effectiveProcess! - ^activeProcess effectiveProcess! Item was changed: ----- Method: ProcessorScheduler>>terminateActive (in category 'process state change') ----- terminateActive "Terminate the process that is currently running." + self activeProcess terminate.! - activeProcess effectiveProcess terminate! From commits at source.squeak.org Mon Mar 15 10:20:17 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:20:17 0000 Subject: [squeak-dev] The Trunk: System-mt.1222.mcz Message-ID: Marcel Taeumel uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-mt.1222.mcz ==================== Summary ==================== Name: System-mt.1222 Author: mt Time: 15 March 2021, 11:20:11.977586 am UUID: 6148616b-707b-654f-8306-990a1e3f3bf6 Ancestors: System-mt.1221 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against System-mt.1221 =============== Item was changed: ----- Method: Process>>debug (in category '*System-debugging') ----- debug + "See the comment in #debugWithTitle:full:contents:." + ^ self debugWithTitle: nil! - ^ self debugWithTitle: 'Debug'! Item was removed: - ----- Method: Process>>debug: (in category '*System-debugging') ----- - debug: context - - ^ self debug: context title: 'Debug'! Item was removed: - ----- Method: Process>>debug:title: (in category '*System-debugging') ----- - debug: context title: title - "Open debugger on self with context shown on top" - - ^ self debug: context title: title full: false - ! Item was removed: - ----- Method: Process>>debug:title:full: (in category '*System-debugging') ----- - debug: context title: title full: bool - - ^ self - debug: context - title: title - full: bool - contents: nil! Item was removed: - ----- Method: Process>>debug:title:full:contents: (in category '*System-debugging') ----- - debug: context title: title full: bool contents: contents - "Open debugger on self with context shown on top" - - | topCtxt | - topCtxt := self isActiveProcess ifTrue: [thisContext] ifFalse: [self suspendedContext]. - (topCtxt hasContext: context) ifFalse: [^ self error: 'context not in process']. - ^ ToolSet debugProcess: self context: context label: title contents: contents fullView: bool! Item was changed: ----- Method: Process>>debugWithTitle: (in category '*System-debugging') ----- debugWithTitle: title + "See the comment in #debugWithTitle:full:contents:." ^ self debugWithTitle: title full: true! Item was changed: ----- Method: Process>>debugWithTitle:full: (in category '*System-debugging') ----- debugWithTitle: title full: aBoolean + "See the comment in #debugWithTitle:full:contents:." ^ self debugWithTitle: title full: aBoolean contents: nil! Item was changed: ----- Method: Process>>debugWithTitle:full:contents: (in category '*System-debugging') ----- debugWithTitle: title full: bool contents: contents + "BEWARE!! Open a debugger on the receiver, which must neither be running nor be simulated. Examples include workspace do-its, test execution, and helper processes. If you want to begin with a certain context, use #runUntil: before calling to here. + + [ 3 + 4 ] newProcess debug. + (Process forBlock: [ 3 + 4 ]) debug. + + Note that for debugging the currently running process, which might currently simulate the receiver, use ProcessorScheduler >> #debugWithTitle:. + + (IMPLEMENTATION NOTE: The debugger interface is capable of debugging the active process correctly. However, unconditionally sending debug messages to the active process, in the past, led to a very tedious number of infinite debugger chains in an edge case when the effectiveProcess differs from the genuineProcess being executed by the VM (see ProcessorScheduler >> #activeProcess). This edge case occurs when a debugger is raised while another process is being simulated (aka process-faithful debugging, see #evaluate:onBehalfOf:), so at the very least Kernel methods should never send this message to the active process. For more information, see http://forum.world.st/I-broke-the-debugger-td5110752.html)" - "Automatically choose the top context." + self assert: [self suspendedContext notNil "= not running"]. + self assert: [self isActiveProcess not "= not even simulated"]. + + ^ ToolSet + debugProcess: self + context: self suspendedContext + label: title + contents: contents + fullView: bool! - ^ self - debug: (self isActiveProcess ifTrue: [thisContext] ifFalse: [self suspendedContext]) - title: title - full: bool - contents: contents! Item was added: + ----- Method: ProcessorScheduler>>debugContext:title:full:contents: (in category '*System-Applications-debugging') ----- + debugContext: aContext title: title full: aBoolean contents: contents + "Open a debugger on the currently running (i.e. genuine) process. Note that that process might actually simulate another process, which ends up here by checking #isActiveProcess. If no code simulation is involved, the genuine process will be suspended along the way -- and hopefully replaced to keep the system responsive. For the simulated case, an existing debugger should take over and leave the genuine process running, that is, simulating. Examples include (a) handling unhandled errors in a tool set and (b) introspecting thisContext to reveal dialog invocation. + + Processor debugWithTitle: 'Debug' full: false contents: 'Carpe Squeak!!' + + Note that, outside code simulation, suspended processes can be debugged directly via Process >> #debugWithTitle:. " + + self assert: [thisContext hasSender: aContext]. + + ^ ToolSet + debugProcess: genuineProcess + context: aContext + label: title + contents: contents + fullView: aBoolean! Item was added: + ----- Method: ProcessorScheduler>>debugContextThat:title: (in category '*System-Applications-debugging') ----- + debugContextThat: aBlock title: title + "See the comment in #debugContext:title:full:contents:." + + ^ self + debugContext: (thisContext sender findContextSuchThat: aBlock) + title: title + full: true + contents: nil! Item was added: + ----- Method: ProcessorScheduler>>debugContextThat:title:full: (in category '*System-Applications-debugging') ----- + debugContextThat: aBlock title: title full: aBoolean + "See the comment in #debugContext:title:full:contents:." + + ^ self + debugContext: (thisContext sender findContextSuchThat: aBlock) + title: title + full: aBoolean + contents: nil! Item was added: + ----- Method: ProcessorScheduler>>debugContextThat:title:full:contents: (in category '*System-Applications-debugging') ----- + debugContextThat: aBlock title: title full: aBoolean contents: contents + "See the comment in #debugContext:title:full:contents:." + + ^ self + debugContext: (thisContext sender findContextSuchThat: aBlock) + title: title + full: aBoolean + contents: contents! Item was added: + ----- Method: ProcessorScheduler>>debugWithTitle: (in category '*System-Applications-debugging') ----- + debugWithTitle: title + "See the comment in #debugContext:title:full:contents:." + + ^ self + debugContext: thisContext sender + title: title + full: true + contents: nil! Item was added: + ----- Method: ProcessorScheduler>>debugWithTitle:full: (in category '*System-Applications-debugging') ----- + debugWithTitle: title full: aBoolean + "See the comment in #debugContext:title:full:contents:." + + ^ self + debugContext: thisContext sender + title: title + full: aBoolean + contents: nil! Item was added: + ----- Method: ProcessorScheduler>>debugWithTitle:full:contents: (in category '*System-Applications-debugging') ----- + debugWithTitle: title full: aBoolean contents: contents + "See the comment in #debugContext:title:full:contents:." + + ^ self + debugContext: thisContext sender + title: title + full: aBoolean + contents: contents! Item was changed: ----- Method: ToolSet class>>debugProcess:context:label:contents:fullView: (in category 'debugging') ----- debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool + "Open a debugger on the given process, which might be active, suspended, or terminated. You can also use the convenience protocol for debugging on Process and ProcessorScheduler. NOTE that you should not pass Processor activeProcess directly to this method. Always use the indirection via ProcessorScheduler >>#debug... See also the comment in Process >> #debugWithTitle:full:contents:." - "Open a debugger on the given process, which might be active, suspended, or terminated." ^ self default + ifNil: [(self confirm: 'Debugger request -- proceed?' translated) ifFalse: [Processor terminateActive]] - ifNil: [(self confirm: 'Debugger request -- proceed?') ifFalse: [Processor terminateActive]] ifNotNil: [:ts | ts debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool]! Item was changed: ----- Method: WrappedBreakpoint>>run:with:in: (in category 'evaluation') ----- run: aSelector with: anArray in: aReceiver | process | process := Process forContext: (Context sender: thisContext sender receiver: aReceiver method: method arguments: anArray) priority: Processor activeProcess priority. + process + debugWithTitle: 'Breakpoint in ' , method methodClass name , '>>#' , method selector. - ToolSet - debugProcess: process - context: process suspendedContext - label: 'Breakpoint in ' , method methodClass name , '>>#' , method selector - contents: nil - fullView: true. Project current spawnNewProcessIfThisIsUI: Processor activeProcess. thisContext swapSender: nil. Processor activeProcess terminate! From commits at source.squeak.org Mon Mar 15 10:20:58 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:20:58 0000 Subject: [squeak-dev] The Trunk: 60Deprecated-mt.92.mcz Message-ID: Marcel Taeumel uploaded a new version of 60Deprecated to project The Trunk: http://source.squeak.org/trunk/60Deprecated-mt.92.mcz ==================== Summary ==================== Name: 60Deprecated-mt.92 Author: mt Time: 15 March 2021, 11:20:56.564586 am UUID: 0255ae66-599c-9a44-94cc-f9979cf1f7c8 Ancestors: 60Deprecated-mt.91 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against 60Deprecated-mt.91 =============== Item was added: + ----- Method: DialogWindow>>findInvocationContext (in category '*60Deprecated-private') ----- + findInvocationContext + + | context | + context := thisContext. + [context method selector = #getUserResponse and: [context isMethodContext]] + whileFalse: [context := context sender]. + ^ context! Item was added: + ----- Method: Process>>debug: (in category '*60Deprecated-System-debugging') ----- + debug: context + + self flag: #deprecated. + ^ self debug: context title: nil! Item was added: + ----- Method: Process>>debug:title: (in category '*60Deprecated-System-debugging') ----- + debug: context title: title + + self flag: #deprecated. + ^ self debug: context title: title full: true! Item was added: + ----- Method: Process>>debug:title:full: (in category '*60Deprecated-System-debugging') ----- + debug: context title: title full: bool + + self flag: #deprecated. + ^ self + debug: context + title: title + full: bool + contents: nil! Item was added: + ----- Method: Process>>debug:title:full:contents: (in category '*60Deprecated-System-debugging') ----- + debug: context title: title full: bool contents: contents + + | topCtxt | + self deprecated: 'ct: Use #debugWithTitle:... to debug the process from its top, "ToolSet debugProcess:..." to customize the entry context, or the debugging protocol on Processor to debug the active process.'. + "See also the comment in #debugWithTitle:full:contents: on debugging the active process." + + topCtxt := self suspendedContext ifNil: [thisContext]. + (topCtxt hasContext: context) ifFalse: [^ self error: 'context not in process' translated]. + ^ ToolSet debugProcess: self context: context label: title contents: contents fullView: bool! Item was changed: ----- Method: ToolSet class>>debugContext:label:contents: (in category '*60Deprecated-debugging') ----- debugContext: aContext label: aString contents: contents + self deprecated: 'ct: Use Processor >> #debugContext:... instead'. + ^ Processor + debugContext: aContext + title: aString + full: false + contents: contents! - self deprecated. - ^ self - debugProcess: Processor activeProcess - context: aContext - label: aString - contents: contents - fullView: false! From commits at source.squeak.org Mon Mar 15 10:22:05 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:22:05 0000 Subject: [squeak-dev] The Trunk: Tools-mt.1031.mcz Message-ID: Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1031.mcz ==================== Summary ==================== Name: Tools-mt.1031 Author: mt Time: 15 March 2021, 11:22:01.998586 am UUID: a69323cb-b4ee-8e4f-963d-780b2d40e73d Ancestors: Tools-mt.1030 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against Tools-mt.1030 =============== Item was changed: ----- Method: Debugger class>>openOn:context:label:contents:fullView: (in category 'opening') ----- + openOn: process context: context label: titleOrNil contents: contentsStringOrNil fullView: bool - openOn: process context: context label: title contents: contentsStringOrNil fullView: bool "Kind of private. Open a notifier or a full debugger in response to an error, halt, or notify. Opens a project-specific debugger. Decorates that invocation with (1) recursive-error detection and (2) error logging, which are both independent from the active GUI framework, that is, MVC or Morphic. Note that clients should debug processes through Process >> #debug instead of calling this method directly." + | ap title | + title := titleOrNil ifNil: ['Debugger' translated]. - | ap | ap := Processor activeProcess. "If the active process re-enters this method again, something went wrong with invoking the debugger." ap hasRecursiveError ifTrue: [ ap clearErrorRecursionFlag. ^ ToolSet handleRecursiveError: title]. "Explicitely handle logging exceptions. No need to bother the recursion mechanism here." [Preferences logDebuggerStackToFile ifTrue: [Smalltalk logSqueakError: title inContext: context] ] on: Error do: [:ex | Preferences disable: #logDebuggerStackToFile. ToolSet debugException: ex]. "If project-specific debuggers mess up, we have to flag that recursion here. Se above." [ap setErrorRecursionFlag. self informExistingDebugger: context label: title. ^ Project current debuggerClass openOn: process context: context label: title contents: contentsStringOrNil fullView: bool ] ensure: [ap clearErrorRecursionFlag].! Item was changed: ----- Method: ProcessBrowser class>>debugProcess: (in category 'process control') ----- debugProcess: aProcess + (aProcess isActiveProcess ifTrue: [Processor] ifFalse: [aProcess]) + debugWithTitle: 'Interrupted from the Process Browser' translated + full: true.! - aProcess debugWithTitle: 'Interrupted from the Process Browser'. - ! Item was changed: ----- Method: StandardToolSet class>>debugProcess:context:label:contents:fullView: (in category 'debugging') ----- debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool + (aProcess isTerminated and: [aString isNil or: [aString beginsWith: 'Debug it']]) ifTrue: [ + ^ Project uiManager inform: 'Nothing to debug. Process has terminated.\Expression optimized.' withCRs translated]. - (aProcess isTerminated and: [aString beginsWith: 'Debug it']) ifTrue: [ - ^ Project uiManager inform: 'Nothing to debug. Process has terminated.\Expression optimized.' withCRs]. ^ Debugger openOn: aProcess context: aContext label: aString contents: contents fullView: aBool! Item was changed: ----- Method: StandardToolSet class>>handleError: (in category 'debugging - handlers') ----- handleError: anError + "Double dispatch. Let the processor take care of that error, which usually calls back here to #debugProcess:..." - "Double dispatch. Let the active process take care of that error, which usually calls back here to #debugProcess:..." + ^ Processor + debugContext: anError signalerContext + title: anError description + full: false + contents: nil! - ^ Processor activeProcess - debug: anError signalerContext - title: anError description! Item was changed: ----- Method: StandardToolSet class>>handleWarning: (in category 'debugging - handlers') ----- handleWarning: aWarning + "Double dispatch. Let the processor take care of that warning, which usually calls back here to #debugProcess:..." - "Double dispatch. Let the active process take care of that warning, which usually calls back here to #debugProcess:..." | message | message := '{1}\\{2}' withCRs asText format: { "First, show the actual text of this warning." aWarning messageText. "Second, append some helpful information that apply to all kinds of warnings." ('{1} {2}' asText format: { 'Select "Proceed" to continue or close this window to cancel the operation.' translated. 'If you do not want to be interrupted anymore, you can {1} this kind of warning. You can also {2}, which resets such warnings on the next image startup.' translated asText format: { "Provide clickable text links so that the user can directly suppress warnings." 'always suppress' asText addAttribute: (PluggableTextAttribute evalBlock: [ aWarning class suppressWarnings. self inform: ('All ''{1}'' warnings will be suppressed.' translated format: {aWarning class name})]). 'suppress temporarily' asText addAttribute: (PluggableTextAttribute evalBlock: [ aWarning class suppressAndResetOnStartUp. self inform: ('All ''{1}'' warnings will be suppressed\and reset on the next image startup.' withCRs translated format: {aWarning class name})])}. }) addAttribute: ( "Show this helpful information in a smaller font." TextFontReference toFont: Preferences standardButtonFont)}. + ^ Processor + debugContext: aWarning signalerContext - ^ Processor activeProcess - debug: aWarning signalerContext title: 'Warning' translated full: false contents: message! From commits at source.squeak.org Mon Mar 15 10:23:19 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:23:19 0000 Subject: [squeak-dev] The Trunk: Morphic-mt.1741.mcz Message-ID: Marcel Taeumel uploaded a new version of Morphic to project The Trunk: http://source.squeak.org/trunk/Morphic-mt.1741.mcz ==================== Summary ==================== Name: Morphic-mt.1741 Author: mt Time: 15 March 2021, 11:23:13.100586 am UUID: 2e5a5c44-9fab-6d41-ba67-e94d99da9a07 Ancestors: Morphic-mt.1740 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against Morphic-mt.1740 =============== Item was added: + ----- Method: DialogWindow>>browseInvocation (in category 'running') ----- + browseInvocation + "Browse the first meaningful invocation method of the receiver." + + self exclusive: false. + + (thisContext findContextSuchThat: self invocationContextPredicate) method browse.! Item was changed: ----- Method: DialogWindow>>debugInvocation (in category 'running') ----- debugInvocation + "Bring up a debugger on the active process, displaying the invocation of the receiver. Strip off irrelevant stack frames that are an implementation detail of the invocation." + self exclusive: false. + + ^ Processor + debugContextThat: self invocationContextPredicate + title: 'Dialog invocation' translated + full: true! - Processor activeProcess - debug: self findInvocationContext - title: 'Dialog invocation'! Item was removed: - ----- Method: DialogWindow>>exploreInvocation (in category 'running') ----- - exploreInvocation - - self exclusive: false. - (self findInvocationContext stack collect: #method) - explore! Item was removed: - ----- Method: DialogWindow>>findInvocationContext (in category 'running') ----- - findInvocationContext - - | context | - context := thisContext. - [context method selector = #getUserResponse and: [context isMethodContext]] - whileFalse: [context := context sender]. - ^ context! Item was added: + ----- Method: DialogWindow>>invocationContextPredicate (in category 'private') ----- + invocationContextPredicate + + | searchPhase hiddenCategories | + self flag: #todo. "ct: Currently, this might cut away a few contexts too much when a dialog window is opened from Morphic code (e.g., SystemWindow>>relabel) directly. With the introduction of UserNotifications, however, this problem will be solved because there will be always an external context between the client and the receiver. See http://forum.world.st/Discussion-Warning-vs-Halt-or-quot-Why-is-a-warning-a-notification-quot-td5106457.html#a5106605 and others." + + searchPhase := true. + hiddenCategories := #('Morphic-Windows' 'ToolBuilder-Kernel' 'ToolBuilder-Morphic' 'ToolBuilder-Morphic-Tools'). + ^ [:ctx | + searchPhase + ifTrue: [ "search invocation context" + (ctx isMethodContext and: [ctx method selector = #getUserResponse]) + ifTrue: [searchPhase := false]. + false] + ifFalse: [ "filter out irrelevant contexts" + (hiddenCategories includes: ctx receiver class category) not]]! Item was changed: ----- Method: DialogWindow>>offerDialogMenu (in category 'running') ----- offerDialogMenu | menu | menu := MenuMorph new defaultTarget: self. menu add: (exclusive == true ifTrue: [''] ifFalse: ['']), 'be modally exclusive' translated action: #toggleExclusive; addLine; + add: 'browse invocation' translated + action: #browseInvocation; + add: 'debug invocation' translated - add: 'explore dialog invocation' translated - action: #exploreInvocation; - add: 'debug dialog invocation' translated action: #debugInvocation. menu popUpEvent: self currentEvent in: self world. [menu isInWorld] whileTrue: [self world doOneSubCycle]. self exclusive ifTrue: [self activeHand newMouseFocus: self].! From commits at source.squeak.org Mon Mar 15 10:24:00 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:24:00 0000 Subject: [squeak-dev] The Trunk: SUnit-mt.125.mcz Message-ID: Marcel Taeumel uploaded a new version of SUnit to project The Trunk: http://source.squeak.org/trunk/SUnit-mt.125.mcz ==================== Summary ==================== Name: SUnit-mt.125 Author: mt Time: 15 March 2021, 11:23:58.176586 am UUID: 07cb8b1a-bf52-274c-b9a4-322a23206152 Ancestors: SUnit-nice.124 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against SUnit-nice.124 =============== Item was changed: ----- Method: TestFailure>>defaultAction (in category 'camp smalltalk') ----- defaultAction + ^ Processor + debugContext: self signalerContext + title: self description + full: false + contents: nil! - Processor activeProcess - debug: self signalerContext - title: self description! From commits at source.squeak.org Mon Mar 15 10:24:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:24:33 0000 Subject: [squeak-dev] The Trunk: EToys-mt.433.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.433.mcz ==================== Summary ==================== Name: EToys-mt.433 Author: mt Time: 15 March 2021, 11:24:26.084586 am UUID: 1972c4e4-1366-0d4d-81de-238053de5fa0 Ancestors: EToys-eem.432 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against EToys-eem.432 =============== Item was changed: ----- Method: EtoysUnhandledError>>devDefaultAction (in category 'priv handling') ----- devDefaultAction + ^ Processor + debugContext: exception signalerContext - Processor activeProcess - debug: exception signalerContext title: exception description full: false + contents: exception messageText! - contents: exception messageText - ! From commits at source.squeak.org Mon Mar 15 10:25:20 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:25:20 0000 Subject: [squeak-dev] The Trunk: ST80Tools-mt.13.mcz Message-ID: Marcel Taeumel uploaded a new version of ST80Tools to project The Trunk: http://source.squeak.org/trunk/ST80Tools-mt.13.mcz ==================== Summary ==================== Name: ST80Tools-mt.13 Author: mt Time: 15 March 2021, 11:25:18.388586 am UUID: 21c1bd8b-9aa9-af45-82ad-dc592a3f9333 Ancestors: ST80Tools-mt.12 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against ST80Tools-mt.12 =============== Item was changed: ----- Method: ParagraphEditor>>debugIt (in category '*ST80Tools') ----- debugIt | receiver context helperProcess | self lineSelectAndEmptyCheck: [^self]. (model respondsTo: #doItReceiver) ifTrue: [receiver := model doItReceiver]. (model respondsTo: #doItContext) ifTrue: [context := model doItContext]. (self compileSelectionFor: receiver in: context) ifNotNil: [:doItMethod | helperProcess := context ifNil: [self assert: doItMethod selector = #DoIt. Process forMethod: doItMethod receiver: receiver] ifNotNil: [self assert: doItMethod selector = #DoItIn:. Process forMethod: doItMethod receiver: receiver arguments: {context}]. + helperProcess debugWithTitle: 'Debug it' translated].! - helperProcess debugWithTitle: 'Debug it'].! From commits at source.squeak.org Mon Mar 15 10:25:58 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:25:58 0000 Subject: [squeak-dev] The Trunk: KernelTests-mt.394.mcz Message-ID: Marcel Taeumel uploaded a new version of KernelTests to project The Trunk: http://source.squeak.org/trunk/KernelTests-mt.394.mcz ==================== Summary ==================== Name: KernelTests-mt.394 Author: mt Time: 15 March 2021, 11:25:56.023586 am UUID: 1abf5d7e-b62f-ee4d-94ea-25d3330a2905 Ancestors: KernelTests-nice.393 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against KernelTests-nice.393 =============== Item was added: + ----- Method: ProcessTest>>genuineProcess (in category 'support') ----- + genuineProcess + + "Usually, we don't want to expose this from the class under test." + ^ Processor instVarNamed: 'genuineProcess'! Item was added: + ----- Method: ProcessTest>>testEvaluateOnBehalfOf (in category 'tests') ----- + testEvaluateOnBehalfOf + + | p1 p2 sem results | + self genuineProcess == Processor activeProcess + ifFalse: [self fail: 'Cannot debug this test']. + + sem := Semaphore new. + p1 := [] newProcess. + p1 environmentAt: #foo put: 1. + p2 := [ + Processor activeProcess environmentAt: #foo put: 2. + results := { + Processor activeProcess environmentAt: #foo. + self genuineProcess environmentAt: #foo. + Processor activeProcess + evaluate: [Processor activeProcess environmentAt: #foo] + onBehalfOf: p1. + Processor activeProcess + evaluate: [self genuineProcess environmentAt: #foo] + onBehalfOf: p1. + Processor activeProcess environmentAt: #foo }. + sem signal + ] newProcess. + + p2 resume. + sem wait. + + self assert: {2. 2. 1. 2. 2} equals: results.! Item was added: + ----- Method: ProcessTest>>testProcessFaithfulRunning (in category 'tests') ----- + testProcessFaithfulRunning + "While simulating a process using #runUntilErrorOrReturnFrom:, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." + + | process result | + process := Process forBlock: [ + result := Processor activeProcess environmentAt: #foo]. + process environmentAt: #foo put: 42. + + process complete: process suspendedContext. + + self assert: 42 equals: result.! Item was added: + ----- Method: ProcessTest>>testProcessFaithfulSimulation (in category 'tests') ----- + testProcessFaithfulSimulation + "While simulating a process using the bytecode simulation machinery, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." + + | process result | + process := Process forBlock: [ + result := Processor activeProcess environmentAt: #foo]. + process environmentAt: #foo put: 42. + + process runUntil: [:context | context isDead]. + + self assert: 42 equals: result.! From commits at source.squeak.org Mon Mar 15 10:26:24 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:26:24 0000 Subject: [squeak-dev] The Trunk: ToolsTests-mt.102.mcz Message-ID: Marcel Taeumel uploaded a new version of ToolsTests to project The Trunk: http://source.squeak.org/trunk/ToolsTests-mt.102.mcz ==================== Summary ==================== Name: ToolsTests-mt.102 Author: mt Time: 15 March 2021, 11:26:23.080586 am UUID: cd7ffa73-b283-8244-85fd-0eef99f698b4 Ancestors: ToolsTests-eem.101 Complements Kernel-mt.1381 Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html =============== Diff against ToolsTests-eem.101 =============== Item was changed: ----- Method: DebuggerTests>>test06DebugSpecificContext (in category 'tests') ----- test06DebugSpecificContext | context | process := [ #(1 2 3) collect: [:ea | ea odd ifTrue: [ ea ] ifFalse: [ Processor activeProcess suspend ] ] ] newProcess. process priority: Processor activeProcess priority + 1. process resume. "Find specific context by following #sender chain." context := process suspendedContext. [context selector = #collect: ] whileFalse: [context := context sender]. + debugger := ToolSet debugProcess: process context: context label: nil contents: nil fullView: true. - debugger := process debug: context. self assert: debugger contextStackTop = context.! Item was changed: ----- Method: DebuggerTests>>test09DebuggerNotifierOrFull (in category 'tests') ----- test09DebuggerNotifierOrFull "Test the defaults." process := [ 3+4 ] newProcess. debugger := process debug. self assert: debugger isFull. debugger close. process := [ 3+4 ] newProcess. debugger := process debugWithTitle: 'Test'. self assert: debugger isFull. debugger close. process := [ 3+4 ] newProcess. + debugger := process debugWithTitle: 'Test 2' full: false. - debugger := process debug: process suspendedContext. self assert: debugger isNotifier.! Item was added: + ----- Method: DebuggerTests>>test16HandleSimulationError (in category 'tests') ----- + test16HandleSimulationError + "Regression test. In the past, the scenario below led to an infinite debugger chain freezing your image. Be careful when running this test in an unpatched image!! For more information, see http://forum.world.st/I-broke-the-debugger-td5110752.html." + + | userProcess | + process := Process forBlock: [ + "the faulty user code" + thisContext pc: nil]. + debugger := process debug. + + [userProcess := [debugger stepThrough] fork. + Processor yield. + + self deny: [process isTerminated]. + self assert: [userProcess isSuspended]] + + ensure: [ + process suspendedContext: nil; terminate. + debugger close. + process := userProcess. + self findDebugger "for correct tearDown"].! Item was added: + ----- Method: DebuggerTests>>test17HandleBlockCannotReturn (in category 'tests') ----- + test17HandleBlockCannotReturn + "Regression test. In the past, the scenario below led to an infinite debugger chain freezing your image. Be careful when running this test in an unpatched image!! For more information, see http://forum.world.st/I-broke-the-debugger-td5110752.html." + + | userProcess | + process := Process forBlock: [ + "the faulty user code" + [] ensure: [thisContext privSender: nil]]. + debugger := process debug. + + [userProcess := [debugger stepOver] fork. + Processor yield. + + self assert: [process isTerminated]. + self deny: [userProcess isRunnable]] + + ensure: [ + process terminate. + debugger close. + process := userProcess. + self findDebugger "for correct tearDown"].! Item was added: + ----- Method: DebuggerTests>>test18HandleNestedBlockCannotReturn (in category 'tests') ----- + test18HandleNestedBlockCannotReturn + "Regression test. In the past, the scenario below led to an infinite debugger chain freezing your image. Be careful when running this test in an unpatched image!! For more information, see http://forum.world.st/I-broke-the-debugger-td5110752.html." + + | metaProcess metaDebugger userProcess | + process := Process forBlock: [ + "the faulty user code" + [] ensure: [thisContext privSender: nil]]. + debugger := process debug. + metaProcess := Process forBlock: [ + debugger stepOver]. + metaDebugger := metaProcess debug. + + [userProcess := [metaDebugger stepOver] fork. + Processor yield. + + self assert: [process isTerminated]. + self deny: [userProcess isRunnable]] + + ensure: [ + process terminate. + debugger close. + metaProcess terminate. + metaDebugger close. + process := userProcess. + self findDebugger "for correct tearDown"].! From commits at source.squeak.org Mon Mar 15 10:37:29 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:37:29 0000 Subject: [squeak-dev] The Trunk: Compiler-tobe.455.mcz Message-ID: Marcel Taeumel uploaded a new version of Compiler to project The Trunk: http://source.squeak.org/trunk/Compiler-tobe.455.mcz ==================== Summary ==================== Name: Compiler-tobe.455 Author: tobe Time: 11 March 2021, 1:50:12.615385 pm UUID: ba3e2f61-8c2a-4dcf-a288-f6e81db4eda1 Ancestors: Compiler-codefrau.454 Fix scanAllTokenPositionsInto: when the text of a comment happened to appear just before it. See testScanTokensRepeatComment for an example. =============== Diff against Compiler-codefrau.454 =============== Item was changed: ----- Method: Scanner>>scanAllTokenPositionsInto: (in category 'expression types') ----- scanAllTokenPositionsInto: aBlock "Evaluate aBlock with the start and end positions of all separate non-white-space tokens, including comments." | lastMark | lastMark := 1. [currentComment ifNotNil: [currentComment do: [:cmnt| | idx | + idx := source originalContents findLastOccurrenceOfString: cmnt startingAt: lastMark. - idx := source originalContents indexOfSubCollection: cmnt startingAt: lastMark. (idx > 0 and: [idx < mark]) ifTrue: [aBlock value: idx - 1 value: (lastMark := idx + cmnt size)]]. currentComment := nil]. mark ifNotNil: [(token == #- and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: [| savedMark | savedMark := mark. self scanToken. token := token negated. mark := savedMark]. "Compensate for the fact that the parser uses two character lookahead. Normally we must remove the extra two characters. But this mustn't happen for the last token at the end of stream." aBlock value: mark value: source position - (aheadChar == DoItCharacter ifTrue: [hereChar == DoItCharacter ifTrue: [0] ifFalse: [1]] ifFalse: [2])]. (tokenType == #rightParenthesis or: [tokenType == #doIt]) ifTrue: [^self]. tokenType == #leftParenthesis ifTrue: [self scanToken; scanAllTokenPositionsInto: aBlock] ifFalse: [(tokenType == #word or: [tokenType == #keyword or: [tokenType == #colon]]) ifTrue: [self scanLitWord. token == #true ifTrue: [token := true]. token == #false ifTrue: [token := false]. token == #nil ifTrue: [token := nil]] ifFalse: [(token == #- and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: [self scanToken. token := token negated]]]. self scanToken ] repeat! From commits at source.squeak.org Mon Mar 15 10:37:49 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 10:37:49 0000 Subject: [squeak-dev] The Trunk: Tests-tobe.445.mcz Message-ID: Marcel Taeumel uploaded a new version of Tests to project The Trunk: http://source.squeak.org/trunk/Tests-tobe.445.mcz ==================== Summary ==================== Name: Tests-tobe.445 Author: tobe Time: 11 March 2021, 1:51:19.457627 pm UUID: e5547bc0-8f7f-4880-b3bc-a18fdb625c3b Ancestors: Tests-mt.444 Complements Compiler-tobe.455 =============== Diff against Tests-mt.444 =============== Item was added: + ----- Method: ScannerTest>>testScanTokensRepeatingComment (in category 'tests') ----- + testScanTokensRepeatingComment + + | ranges | + ranges := Array streamContents: [:stream | + Scanner new scanTokenPositionsIn: '''packages''. "packages" 222' into: [:start :end | stream nextPut: (start to: end)]]. + + self assert: (ranges hasEqualElements: {1 to: 10. 11 to: 11. 13 to: 22. 24 to: 26. (27 to: 26)})! From m at jaromir.net Mon Mar 15 10:45:05 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 15 Mar 2021 05:45:05 -0500 (CDT) Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> <1615667409182-0.post@n4.nabble.com> <1615758576373-0.post@n4.nabble.com> <1615764104533-0.post@n4.nabble.com> Message-ID: <1615805105418-0.post@n4.nabble.com> Hi Marcel, >> The only point I'm making is there are real pathological situations where >> you might want to see the genuine process while another process acts as >> the >> active process and considering it terminated is very confusing. > So, you see no problems in merging this change into Trunk? Of course I'm not objecting merging the change, it's great :) Sorry for mixing this up with the "genuineProcess isTerminated = true", I haven't realized it was an issue until just recently. It is totally independent and was there even before, with Processor activeProcess behaving the same. Thanks again, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Mon Mar 15 12:52:08 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 15 Mar 2021 12:52:08 0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1382.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1382.mcz ==================== Summary ==================== Name: Kernel-ct.1382 Author: ct Time: 15 March 2021, 1:52:03.249869 pm UUID: e108423f-661f-4d4f-9ad8-c667c3995b32 Ancestors: Kernel-mt.1381 Proposal: Revises usage and handling of primitive 19, also known as the simulation guard. Don't use it in #newProcess and variants since they don't involve any actual control logic. Instead, also show a simulation warning when debugging a control primitive (primitiveSignal primitiveWait primitiveResume primitiveSuspend). Improves integration of simulation guard warnings by signaling a Warning on the simulator stack rather than spawning a debugger on the debugged process. This also makes it easier to handle these warnings in a non-interactive context. See http://forum.world.st/Simulation-guard-lt-primitive-19-gt-crashes-the-image-td5127443.html and http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html for more information. Reuploaded to resolve merge conflict with Kernel-mt.1381. Replaces Kernel-ct.1381, which can be moved into the treated inbox. =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + ["Transcript + cr; + nextPutAll: 'Processor activeProcess '; + nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); + nextPutAll: ' owner'; + flush." + value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! From gettimothy at zoho.com Mon Mar 15 17:24:29 2021 From: gettimothy at zoho.com (gettimothy) Date: Mon, 15 Mar 2021 13:24:29 -0400 Subject: [squeak-dev] A <- B{C} Cardinality Stop Expression behavior question for XTreams-Parsing Message-ID: <17836eaee2a.f0f0e08216009.1934764439290560278@zoho.com> Hi Folks, I am getting some unexpected behaviour from  XTreams-Parsing Stop Expression. >From my notes, I am expecting: {E}     Cardinality:  Stop Expression A <- B{C} to accept A,  means, accept any number of B up until E comes. Consume E too, but don't yield it. So, such expression accepts: BE, BBE, BBBE, BBBBE, etc, and yields B, BB, BBB, BBBB, etc. I am parsing Wikimedia Free Links...some text enclosed in brackets that I transform into an anchor on the rule callback. [[this is a free link]] This rule works....  LinkFreeUnCaptioned <- OPEN_BRACKET{2} [^\]\|]+ "]]" It invokes the callback when encountering two open brackets then eat any text except the pipe and the close bracket and continue until you hit two close brackets. works great. However.... LinkFreeUnCaptioned <- OPEN_BRACKET{2} [^\]\|]{"]]"} works great too...EXCEPT It also works when there is NO pair of closing brackets. i.e. [[this is a free link]] is correctly parsed, but [[this is a free link is ALSO parsed, even though there are not closing "]]"' I am not sure if my expectation is incorrect or if this is a bug. Thank you for your time. Below is a (debugging version) of the callback for the above rule: LinkFreeUnCaptioned:  anOrderedCollection       "https://en.wikipedia.org/wiki/Help:Wikitext#Free_links"       | link caption url xml|       url := caption := anOrderedCollection joinSeparatedBy:''.       self break.       link := (WikitextLink default  linkFree: url caption: caption).       xml := self       newElementTag: Anchor             attributes:             (Array with: Href -> ((link baseurl), (link url)) with: Classs -> (link claass joinSeparatedBy:'') with: Title -> (link title))             elements: (Array with: (self newText: (link title))).       transcripton ifTrue:[Transcript show:'LinkFreeUnCaptioned';cr. ]. ^xml -------------- next part -------------- An HTML attachment was scrubbed... URL: From lproven at gmail.com Mon Mar 15 17:30:09 2021 From: lproven at gmail.com (Liam Proven) Date: Mon, 15 Mar 2021 18:30:09 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here Message-ID: https://twitter.com/jamescham/status/1370955307799613441?s=20 I retweeted it. A friend of mine responded thus: « Ludicrous price, image based persistence making software distribution a nightmare, trivial 'image wide' malware, and the inability to run anything not written in smalltalk. And 'No'. » The price is now moot since there are multiple FOSS implementations, but a couple of the other points seem quite telling... or do they? -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From tim at rowledge.org Mon Mar 15 17:43:05 2021 From: tim at rowledge.org (tim Rowledge) Date: Mon, 15 Mar 2021 10:43:05 -0700 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: <0F6C5958-A4DF-427B-BFF4-360FD6EE36CF@rowledge.org> > On 2021-03-15, at 10:30 AM, Liam Proven wrote: > > https://twitter.com/jamescham/status/1370955307799613441?s=20 > > I retweeted it. A friend of mine responded thus: > > « > Ludicrous price, image based persistence making software distribution > a nightmare, trivial 'image wide' malware, and the inability to run > anything not written in smalltalk. And 'No'. > » > > The price is now moot since there are multiple FOSS implementations, > but a couple of the other points seem quite telling... or do they? Nope. They're utterly wrong in a wrongness level rarely achieved. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim A bug in the code is worth two in the documentation. From lproven at gmail.com Mon Mar 15 17:56:19 2021 From: lproven at gmail.com (Liam Proven) Date: Mon, 15 Mar 2021 18:56:19 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: <0F6C5958-A4DF-427B-BFF4-360FD6EE36CF@rowledge.org> References: <0F6C5958-A4DF-427B-BFF4-360FD6EE36CF@rowledge.org> Message-ID: On Mon, 15 Mar 2021 at 18:43, tim Rowledge wrote: > > Nope. They're utterly wrong in a wrongness level rarely achieved. Go on, please. I am eager to know _why_. -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From m at jaromir.net Mon Mar 15 20:54:40 2021 From: m at jaromir.net (Jaromir Matas) Date: Mon, 15 Mar 2021 15:54:40 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> Message-ID: <1615841680085-0.post@n4.nabble.com> Hi Marcel, >> In this discussion, you should always specify whether "responds to" >> involves a sender within a simulated or genuine "context". ;-) I am still >> not convinced that this is an actual problem. Sorry for confusing you, this all new to me :) How can I convince you? I debug quite naively, no fancy stuff. I'll try again to show the exact steps replicating the issue using Christoph's example: 0. downloaded the latest trunk image Squeak6.0alpha-20304-64bit-202003021730-Windows with Kernel-mt.1381 1. open Process Browser with auto-update on 2. open an explorer window on the current UI process to watch it 3. do-it `[self error: 'e1'] ensure: [^2]` in a Workspace Now three things happened, as expected (screenshot 1): a) an Error debugger window popped up a) the UI process has become suspended b) a new UI has been created 4. open an explorer window on the new UI process to watch it 5. Abandon the Error window And now a couple of highly surprising things happened (screenshot 2): d) Error window disapeared - that's still expected but e) the new UI process (88230) disappeared from the Process Browser - NOT expected AND became the genuineProcess - expected AND it responds true to isTerminated sent to self in its Explorer window - NOT expected f) the old UI process (48259) became the current UI process - NOT expected AND became the effectiveProcess - NOT expected AND responds true to isActiveProcess sent to self in its Explorer window - confusing At this point however the genuine process is indeed not terminated but executing. It is not shown on the Process Browser however because it filters out terminated processes. You can verify this by changing first line in isTerminated, for a moment, to: (self isActiveProcess or: [self effectiveProcess == Processor activeProcess]) ifTrue: [^ false]. And now everything runs as usual as if nothing happened except the really executing process is hidden from your view and the formerly debugged process acts as the active process but is not really executing (see screenshot 3 with the invisible process 88230 shown). 6. now I reverted isTerminated back to original and did Christoph's do-it `self error` And the rest went as Christoph described; I'd just like to point out the hidden process 88230 now reappears as the current UI process and correctly responds true to isActiveProcess e.g. in the Explorer window. In case you hit Proceed on the Unwind error window the two UI processes above will start alternating because they are now both runnable in the priority 40 queue. I find this course of events very unexpected; trying to follow using the standard tools is very confusing - namely the disappearing genuine process. I know it's due to the bug Christoph discovered and described but the tools should rather reveal, not hide information vital for understanding what's happening :) I apologize for such a long description and sincerely hope I haven't made any error here to waste your time. Thanks, Screenshot1.png Screenshot2.png Screenshot3.png ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Tue Mar 16 08:14:18 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 16 Mar 2021 09:14:18 +0100 Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615841680085-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> Message-ID: Hi Jaromir. > How can I convince you? Well, I understand the issue that you described. However, I think it is very bad style to return from within an ensure-block. That's why I would like to set the urgency for this to "rather low". :-) The idiom for using #ensure: in the return-expression is this: ^ aBlock ensure: ensureBlock ^ [ self doTrickyStuff ] ensure: [ self cleanUp ] That is, you should only use *inner* returns to get out early. And then, the ensure will clean up after you. If you really would want to "ensure" a certain return value, you could do it like this: | result | [ self doTrickyStuff ] ensure: [ result := 42 ]. ^ result But why using #ensure: at all for such a case? If you think that exceptions might happen, you would have to wrap it this way: | result | result := 42. [ self doTrickyStuff ] on: KnownError do: [ :ex | "Ignore." ]. ^ result Well, doesn't make much sense to me. :-) You clean up resources (i.e. state) via #ensure: when facing exceptions. You do not manage control flow through it. The exception handlers #on:do: are for that. Do not put a return "^" into an ensure block. Best, Marcel Am 15.03.2021 21:54:47 schrieb Jaromir Matas : Hi Marcel, >> In this discussion, you should always specify whether "responds to" >> involves a sender within a simulated or genuine "context". ;-) I am still >> not convinced that this is an actual problem. Sorry for confusing you, this all new to me :) How can I convince you? I debug quite naively, no fancy stuff. I'll try again to show the exact steps replicating the issue using Christoph's example: 0. downloaded the latest trunk image Squeak6.0alpha-20304-64bit-202003021730-Windows with Kernel-mt.1381 1. open Process Browser with auto-update on 2. open an explorer window on the current UI process to watch it 3. do-it `[self error: 'e1'] ensure: [^2]` in a Workspace Now three things happened, as expected (screenshot 1): a) an Error debugger window popped up a) the UI process has become suspended b) a new UI has been created 4. open an explorer window on the new UI process to watch it 5. Abandon the Error window And now a couple of highly surprising things happened (screenshot 2): d) Error window disapeared - that's still expected but e) the new UI process (88230) disappeared from the Process Browser - NOT expected AND became the genuineProcess - expected AND it responds true to isTerminated sent to self in its Explorer window - NOT expected f) the old UI process (48259) became the current UI process - NOT expected AND became the effectiveProcess - NOT expected AND responds true to isActiveProcess sent to self in its Explorer window - confusing At this point however the genuine process is indeed not terminated but executing. It is not shown on the Process Browser however because it filters out terminated processes. You can verify this by changing first line in isTerminated, for a moment, to: (self isActiveProcess or: [self effectiveProcess == Processor activeProcess]) ifTrue: [^ false]. And now everything runs as usual as if nothing happened except the really executing process is hidden from your view and the formerly debugged process acts as the active process but is not really executing (see screenshot 3 with the invisible process 88230 shown). 6. now I reverted isTerminated back to original and did Christoph's do-it `self error` And the rest went as Christoph described; I'd just like to point out the hidden process 88230 now reappears as the current UI process and correctly responds true to isActiveProcess e.g. in the Explorer window. In case you hit Proceed on the Unwind error window the two UI processes above will start alternating because they are now both runnable in the priority 40 queue. I find this course of events very unexpected; trying to follow using the standard tools is very confusing - namely the disappearing genuine process. I know it's due to the bug Christoph discovered and described but the tools should rather reveal, not hide information vital for understanding what's happening :) I apologize for such a long description and sincerely hope I haven't made any error here to waste your time. Thanks, Screenshot1.png Screenshot2.png Screenshot3.png ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 16 08:45:14 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 16 Mar 2021 09:45:14 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: Hi Liam. > [...] but a couple of the other points seem quite telling... or do they? Is this a typical low-effort "You tell me why I should care?"-situation? :-) Well, if you want to figure out whether your friend is right or wrong, you could try creating a non-trivial thing in Squeak. This involves getting to know the entire system, not just the Smalltalk language and standard library. You would have to figure out how Squeak's tools work and how to shorten the feedback cycle to the level you are most comfortable with. --- After that, you are qualified to ponder about what modern Web browsers (+ DOM/CSS/JavaScript) have achieved yet, and what they still miss. Maybe also include the motivation behind Docker and containerization in general. Just kidding. :-) Or am I? Best, Marcel Am 15.03.2021 18:30:31 schrieb Liam Proven : https://twitter.com/jamescham/status/1370955307799613441?s=20 I retweeted it. A friend of mine responded thus: « Ludicrous price, image based persistence making software distribution a nightmare, trivial 'image wide' malware, and the inability to run anything not written in smalltalk. And 'No'. » The price is now moot since there are multiple FOSS implementations, but a couple of the other points seem quite telling... or do they? -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 16 08:55:15 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 16 Mar 2021 09:55:15 +0100 Subject: [squeak-dev] The Inbox: Kernel-ct.1382.mcz In-Reply-To: References: Message-ID: +1 Also see Magnitude >> #between:and: :-) Best, Marcel Am 15.03.2021 13:52:19 schrieb commits at source.squeak.org : A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1382.mcz ==================== Summary ==================== Name: Kernel-ct.1382 Author: ct Time: 15 March 2021, 1:52:03.249869 pm UUID: e108423f-661f-4d4f-9ad8-c667c3995b32 Ancestors: Kernel-mt.1381 Proposal: Revises usage and handling of primitive 19, also known as the simulation guard. Don't use it in #newProcess and variants since they don't involve any actual control logic. Instead, also show a simulation warning when debugging a control primitive (primitiveSignal primitiveWait primitiveResume primitiveSuspend). Improves integration of simulation guard warnings by signaling a Warning on the simulator stack rather than spawning a debugger on the debugged process. This also makes it easier to handle these warnings in a non-interactive context. See http://forum.world.st/Simulation-guard-lt-primitive-19-gt-crashes-the-image-td5127443.html and http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html for more information. Reuploaded to resolve merge conflict with Kernel-mt.1381. Replaces Kernel-ct.1381, which can be moved into the treated inbox. =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + ["Transcript + cr; + nextPutAll: 'Processor activeProcess '; + nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); + nextPutAll: ' owner'; + flush." + value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 11:21:05 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 11:21:05 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Message-ID: Hi all! :-) I'm very excited to finally share my new project with you today, which I call SimulationStudio and have made available on GitHub under [1]. Its primary function is to provide an inheritable SimulationContext subclass of Context that makes it easy to simulate entire call trees while customizing the execution or installing custom hooks for various tracing and measurement purposes. Another accomplishment is the Sandbox which allows you to run arbitrary Smalltalk code in an isolated environment, separating any side effects that occur during the simulation from the rest of the image. Sandbox The original idea has arisen already one and a half years ago when we were discussing the necessary restrictions of the current MethodFinder design, which uses a huge allow-list of selectors that can be safely performed on unknown objects without the risk of dangerous side effects [2]. It was Eliot who proposed to apply simulation to this problem in order to run the unknown code step-by-step and prevent any side effects. I liked this idea very much and recently was finally able to build a working Sandbox prototype. However, instead of only aborting execution or creating a snapshot when a side effect is reached, I implemented an indirection layer for all side effects so that while the side effects are not actually applied to the entire image, they will be transparently available from the perspective of the code under simulation. Here is a simple application example: World color: Color transparent. World color isTransparent. If we execute these statements regularly, in the PasteUpMorph, the instance variable color will be set to transparent, then it will be accessed again and sent the message #isTransparent which will eventually be answered true. However, in this example, your global image state would also be affected, and your wonderful desktop decorations would have been erased irrecoverably. If you only want to find out what the code above returns, you can now run it in an isolated sandbox without actually impairing your image: Sandbox evaluate: [ World color: Color transparent. World color isTransparent]. The script will answer true, again, but this time the world's actual color won't have changed. And here is how it works: The sandbox uses a SandboxContext under the hood, which is a subclass of Context that is only meant to be used for simulation purposes. This SandboxContext overrides a number of simulation operations, including #object:instVarAt:put: for writing and #object:instVarAt: for reading instance variables. Now, when an attempt is made to produce a side effect by assigning a new value to the color instvar in PasteUpMorph, the SandboxContext notices this attempt and adds the object (World) to the sandbox space, which is just a big WeakIdentityKeyDictionary that maps real-world objects to sandbox-manipulated objects. The actual manipulation then is only applied to the sandbox-manipulated copy of the original object, so the rest of the image does not get affected. Analogously, #object:instVarAt: checks whether the requested object is already part of the sandbox space, and if this is true, it redirects the instvar request to the sandboxed version of the original object. Of course, these indirections are not only implemented for instance variable accesses but also many other bytecode operations such as variable object access (#at:[put:]), identity exchanging/forwarding, instance adoption, and many other VM primitives and modules. By this means, the sandbox space is extended dynamically on demand and all side effects caused by the sandboxed code remain locally in the sandbox environment without affecting the rest of the image. Sandboxes are thread-safe (i.e. global-state free) and self-transparent, i.e. you can even do the following: Sandbox evaluate: [Sandbox evaluate: [6 * 7]]. SimulationContext A central idea while implementing the SandboxContext was to inherit from the regular Context class in order to reuse the existing simulation logic. However, subclassing from Context is not straightforward due to the special role it plays in the connection to the VM Executor (shortly, Context instances are only created on demand for optimization purposes). Eliot wrote a really worthwhile description of this mechanism in [3] recently. Some context primitives and the stack functionality which is used by most bytecode operations won't work in a plain subclass of Context. For this reason, I have created the SimulationContext subclass of Context which overrides these functionalities by providing purely image-based implementations. Another responsibility of SimulationContext is to preserve the class of context instances while simulating a call stack - that is, new stack frames that are created when simulating a message send are automatically converted to instances of the current SimulationContext class, too. With this base, it is fairly easy to create subclasses of SimulationContext to customize simulation at will, without needing to deal with any further VM magic. So does SandboxContext, but I also created another subclass just for proof of concept, SimulationMsrContext, which integrates with the MessageSendRecorder of the HPI group [4, 5] but provides a complete trace of all message sends. At the same time, SimulationMsrContext eliminates the need for installing and uninstalling global MethodWrappers in the image (which is an exclusive operation and can be slow at some times) and thus makes it even possible to transparently trace the simulation itself. Note that this only a rough experiment with some hick-ups and the concepts do not match each other perfectly. From a long-term perspective, something like a BytecodeBrowser might provide an even more detailed trace of the execution. While SimulationContexts cannot be executed by the VM any longer, I wrote a small debugging adapter, making it possible to debug all kinds of SimulationContext in a regular debugger (see the debugging extensions on Context class). You can also debug the implementation of the SimulationContext from there by loading the BytecodeDebugger changeset [6]. Applications I think SimulationStudio opens or at least facilitates a bunch of possibilities around the exciting simulation machinery of Squeak. I already have identified some real use cases for the sandbox: * An alternative MethodFinder implementation that is not restricted to an allow-list of selectors as mentioned above. A prototype for this is available in the repository on the class-side of Sandbox. Example: Sandbox findSelectorsFor: {1. 2. 3. 4} arguments: {[:x | x asWords] ascending} thatAnswer: {4. 1. 3. 2}. "==> #(quickSort: sort: sorted:)" The implementation itself is noticeably simple: | selectors | selectors := receiver class allSelectors select: [:sel | sel numArgs = arguments size]. ^ Generator on: [:generator | selectors do: [:sel | | match sandbox | sandbox := Sandbox new. sandbox stepLimit: 100000. match := sandbox evaluate: [ | result | result := (receiver perform: sel withArguments: arguments). result = expectedResult] ifFailed: [false]. match ifTrue: [generator nextPut: sel] ] ] As you can see, it would be also a small change only to find methods based on side effects instead on its return value. * Type-guessing support for Autocompletion: Autocompletion by Leon Matthes [7] is a code completion implementation for Squeak based on eCompletion [8] that, inter alia, provides type guessing based on previously entered literals that are recognized as the receiver, instance variables, global bindings, or quick return selectors. By combining this idea with the possibility of running arbitrary code in a sandbox, the quality of type guessing and thus completion suggestions can be improved significantly for long expressions in a scripting environment. My long-term vision in this regard is to provide a UI that is equal or superior to the code completion into Chrome Dev Console. :-) I have available an okayish patch (< 20 lines!) for this in my image and can share you a changeset on demand, but it still requires some fine polish before I will officially release it. * I already have many other ideas around dynamic code analysis (for instance, fine-granular execution tracing, logging of side effects, bytecode-specific coverage measurements, revertable debugger stepping, ...) and will definitively have some more fun in this field in the near future. If you are interested, you can watch the repository on GitHub. :-) Limitations and challenges Well, first of all ... performance. :-) Some recent measurements that I have run have shown that the simulator reaches about 0.1 percent (sic) of the speed of the VM executor, depending on the domain and the distribution of bytecode operations. The layers added on top of the simulator by SimulationStudio, moreover the fact that I did not yet run any systematic attempts on optimization, slow down the execution even more by further ~50%. While it's still "fast enough for our neurons" in most scenarios I came up with so far, computation-intensive operations such as rendering 4K images can indeed require a certain amount of patience. However, from a conceptual perspective, I comfort myself by saying that this is "only" an optimization problem. Another challenge is the handling of primitive operations during the sandbox execution. At the moment, I have disabled most primitives that I did not need and tried to fall back on image implementations whenever possible (see SandboxContext >> #doPrimitive:method:receiver:args: and #doNamedPrimitiveIn:for:withArgs:). However, for some areas, mostly external I/O plugins, this is not possible, and some customized solutions will be required to provide these functionalities while running in an isolated sandbox context. Last but not least, it's hard to preserve a consistent sandbox space while making modifications in the real image. Just take the code example from above and wonder what should happen when the color of the world is changed half-way during the execution. Should the sandboxed copy of the world be affected, too? It is not possible to track changes to the real image space without severe performance drawbacks. This is a synchronization issue for which I don't know a good solution, yet. I want you! :-) This is an ongoing project and I'm looking very much forward to your feedback, questions, and ideas on this matter! If you are looking for a challenge, you can try to find a gap in the sandbox isolation. I have spent many hours sealing it in all conscience, I did not check everything systematically so I would not be very surprised (but delighted!) if you manage to find any vulnerability. Ideally, any kind of contribution will be welcome too, of course - just create your issues and pull requests in the repository at [1]! :-) Carpe Squeak! Best, Christoph PS: Sorry for the long text. I thank everyone who made it this far. :-) [1] https://github.com/LinqLover/SimulationStudio [2] http://forum.world.st/MethodFinder-Blocks-tp5105421p5105623.html [3] http://forum.world.st/Two-new-curious-Context-primitive-questions-tp5125779p5125783.html [4] https://github.com/hpi-swa/MessageSendRecorder [5] http://forum.world.st/ANN-MessageSendRecorder-and-MethodWrappers-GitHub-td5120077.html [6] http://forum.world.st/Changeset-Concept-BytecodeDebugger-3-cs-tp5110352.html [7] https://github.com/LeonMatthes/Autocompletion [8] https://uncomplex.net/ecompletion/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 11:22:46 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 11:22:46 +0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1382.mcz In-Reply-To: References: , Message-ID: > Also see Magnitude >> #between:and: :-) Yeah, I was aware of this, but #between:and: is not inlined ... Probably this was a case of premature optimization. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 16. März 2021 09:55:15 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Kernel-ct.1382.mcz +1 Also see Magnitude >> #between:and: :-) Best, Marcel Am 15.03.2021 13:52:19 schrieb commits at source.squeak.org : A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1382.mcz ==================== Summary ==================== Name: Kernel-ct.1382 Author: ct Time: 15 March 2021, 1:52:03.249869 pm UUID: e108423f-661f-4d4f-9ad8-c667c3995b32 Ancestors: Kernel-mt.1381 Proposal: Revises usage and handling of primitive 19, also known as the simulation guard. Don't use it in #newProcess and variants since they don't involve any actual control logic. Instead, also show a simulation warning when debugging a control primitive (primitiveSignal primitiveWait primitiveResume primitiveSuspend). Improves integration of simulation guard warnings by signaling a Warning on the simulator stack rather than spawning a debugger on the debugged process. This also makes it easier to handle these warnings in a non-interactive context. See http://forum.world.st/Simulation-guard-lt-primitive-19-gt-crashes-the-image-td5127443.html and http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html for more information. Reuploaded to resolve merge conflict with Kernel-mt.1381. Replaces Kernel-ct.1381, which can be moved into the treated inbox. =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + ["Transcript + cr; + nextPutAll: 'Processor activeProcess '; + nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); + nextPutAll: ' owner'; + flush." + value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 16 12:23:42 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 16 Mar 2021 07:23:42 -0500 (CDT) Subject: [squeak-dev] Please try out | Fixes for debugger invocation during code simulation In-Reply-To: <1615805105418-0.post@n4.nabble.com> References: <3c256dd35dd147f5838090546f1987b6@student.hpi.uni-potsdam.de> <1615667409182-0.post@n4.nabble.com> <1615758576373-0.post@n4.nabble.com> <1615764104533-0.post@n4.nabble.com> <1615805105418-0.post@n4.nabble.com> Message-ID: <1615897422001-0.post@n4.nabble.com> Hi Jaromir, sorry for the late reply! I very much appreciate your feedback on these things. :-) Just for clarification, under normal circumstances, #isTerminated seems to work as expected. If you debug the UI process (e.g., by evaluating "self halt"), both the process being debugged and the debugging process answer #false when sent #isTerminated. The only exception from this rule appears to occur when the Processor >> #evaluate:onBehalfOf: logic does not get unwound correctly so the effectiveProcess is not reset, which is a consequence of the bug I described in [1]. Unfortunately, there is even another way to reproduce this problem by corrupting the stack of the simulated process and then debugging it using #runUntilErrorOrReturnFrom:, for instance by stepping over a method that does "thisContext privSender: nil" - see also [2] about this concern. In this situation, a "cannot return" error is shown and after terminating it, the debugged process keeps answering false when sent #isTerminated. I think this is also related to the thread you started in [3]. Let's continue discussing these issues in the relevant threads - I'll add my two cents there soon! However, nothing of these issues is a regression of the changeset proposed in this thread. :-) We only renamed a few things (activeProcess to genuineProcess) and refactored the accessors, but the conceptional logic of process-faithful debugging has not been changed. Still, missing resets of the effectiveProcess are indeed a general problem, and at least in the event of a #cannotReturn:, there is no chance to unwind #evaluate:onBehalfOf: properly. While we should fix the actual simulation issues, I wonder whether we can and whether we should find a way to heal processes again after a missing reset. A simple heuristic could be setting the effectiveProcess to nil in every process that does not have an #evaluate:onBehalfOf: context on its stack. Hypothetically, we could install a workaround for this check in #isTerminated. Thinking more radically, we could also replace the effectiveProcess variable with a stateless scoping exception analogously to CurrentReadOnlySourceFiles, but this would affect performance. Also, I'm not sure whether a process is automatically invalidates as soon as the #evaluate:onBehalfOf: disappears from its stack during simulation - just think of coroutines as used by the Generator, probably they would be a legal operation as long as #evaluate:onBehalfOf: will appear on the stack again at the end of the simulation. Questions over questions ... Maybe you have some other good ideas here. :-) Best, Christoph [1] http://forum.world.st/Bug-in-Process-gt-gt-terminate-Returning-from-unwind-contexts-td5127570.html [2] http://forum.world.st/BUG-REGRESSION-while-debugging-Generator-gt-gt-nextPut-td5108125.html [3] http://forum.world.st/Refactoring-terminate-to-get-rid-of-cannot-return-errors-etc-td5127732.html ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 16 12:34:41 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 16 Mar 2021 07:34:41 -0500 (CDT) Subject: [squeak-dev] The Inbox: Kernel-jar.1381.mcz In-Reply-To: References: Message-ID: <1615898081632-0.post@n4.nabble.com> +1 on this change. If you want to act in an exemplary manner, it would be great if you could submit a test case for this in ProcessTest in a new inbox version by using the example you mentioned in [1]. :-) Best, Christoph [1] http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-tp5127335p5127336.html ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From kksubbu.ml at gmail.com Tue Mar 16 13:21:16 2021 From: kksubbu.ml at gmail.com (K K Subbu) Date: Tue, 16 Mar 2021 18:51:16 +0530 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: Message-ID: On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu From lproven at gmail.com Tue Mar 16 13:27:47 2021 From: lproven at gmail.com (Liam Proven) Date: Tue, 16 Mar 2021 14:27:47 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: On Tue, 16 Mar 2021 at 09:45, Marcel Taeumel wrote: > > Hi Liam. > > > [...] but a couple of the other points seem quite telling... or do they? > > Is this a typical low-effort "You tell me why I should care?"-situation? :-) :-( Well, no. I did present a talk advocating Smalltalk as a possible basis for a next-generation OS just last month and have discussed it at some length on this ML. But I am not in any way an expert in it. I tweeted about it, and now Twitter is showing me tweets about Smalltalk, including this one. Honestly, I hoped that some Squeak practitioners here might want to go and engage themselves, or perhaps even suggest things I could counter this negativity with. > Well, if you want to figure out whether your friend is right or wrong, you could try creating a non-trivial thing in Squeak. This involves getting to know the entire system, not just the Smalltalk language and standard library. You would have to figure out how Squeak's tools work and how to shorten the feedback cycle to the level you are most comfortable with. --- After that, you are qualified to ponder about what modern Web browsers (+ DOM/CSS/JavaScript) have achieved yet, and what they still miss. Maybe also include the motivation behind Docker and containerization in general. > > Just kidding. :-) Or am I? "Go and see for yourself" is sadly a very common rejoinder when asking programmers for information about programming languages, but it is pretty much never a helpful one. :-( -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 16 13:36:37 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 16 Mar 2021 08:36:37 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> Message-ID: <1615901797162-0.post@n4.nabble.com> Hi Jaromir, again, very sorry for keeping you waiting for so long time. I'll try to go through your questions step by step, hoping everything is still relevant: :-) > It seems to me after `ctxt restart` the thread never returns back so the > assignment is moot? Fair question. After evaluating "[self error] ensure: [^1]", abandoning the debugger, and raising another error, the relevant #terminate context is indeed dead, so somehow the "ctxt restart" appears to have returned indeed ... But I don't know why. :) (By the way, in case you did not yet find this out by yourself, you can find the activated #terminate context by exploring the second-bottommost context (#ensure:) of the UI process and navigating up in the sender stack of its aBlock argument's outerContext ... ) > At any rate it seems to me the problem is not related to non-local returns > exclusively. Other scenario I have now: > x:=nil. [self error: 'x1'] ensure: [[self error: 'x2'] ensure: [[self > error: 'x3'] ensure: [x:=3]. x:=2]. x:=1]. > x Oh no. Important findings, though! This enlarges the issue we are discussing here. Returning from unwind contexts *could* be considered as something stupid and illegal as I wrote above, but raising errors from them is something much more likely. Even non-Smalltalkish languages such as Python support this and receiving unwind errors in these situations has always appeared as a sad limitation to me. Hm ... in this example, my changeset raises a #cannotReturn: after abandoning all the debuggers. :/ ((Side note: Maybe we should tackle ExceptionTests>>testHandlerFromAction these days, too. However, not sure whether they are later to each other, thus the double brackets :))) > If you Abandon the FIRST error debugger - do you expect to continue to the > second debugger, abandon it and continue to the third debugger or rather > quit right after the FIRST debugger Abandon? If the former then what would > the difference between Proceed and Abandon be? In my mental model, these debuggers form a (virtual) stack. Maybe thinks would get clearer if we would only delete the debugger window after the termination had been completed. I tell the first debugger to abandon - during the abandoning, another error occurs, and a second debugger informs me about this incident - I tell it to abandon, too - so what exactly did I abandon now? The unwind handling (i.e. a single unwind block) or rather the unwinding activity itself (which would be equivalent to continue the regular execution)? Let's assume the first one for now ... And finally, the third debugger appears because a second unwind block raised an error - I tell it to continue, meaning that the unwind handling should be resumed right from the place where the error has occurred, so in the end, the termination should be continued. Phew! What do you think about this example? ;-) > What is the expected semantics of the Debugger's Abandon? To quit and do > nothing more to the debugged process or continue unwinding? I have to agree with Levente here that unwinding should not be skipped here definitively. Abandoning is used every often when an error occurs and it's a fundamental meaning of #ensure: contexts to be executed even if the regular execution is not being continued, giving their senders the chance to clean up things. And regarding your proposal of enforcing termination: > >>> [interruptedProcess isTerminated] whileFalse: [interruptedProcess terminate]. I'm not sure whether this would be a good idea, though ... The debugger is only a graphical tool that makes process control more easily. IMHO Debugger >> #abandon should have exactly the same effect as Process >> #terminate. So the next question would be whether we would want such an enforce loop directly in Processor >> #terminate. I don't know. tl;dr: Unwind errors are a problem, but my proposed changeset is not really suitable to fix all of them. Should we probably just stick with the UnhandledError handling from within Process >> #terminate? This only seems to be necessary for calls from the Debugger (see Debugger >> #stepOver). And with regard to the returns from unwind contexts, here is another vague idea: Could it help us in any way to raise a second exception from #aboutToReturn:through: to keep senders such as Process >> #terminate informed? Or would this just be unnecessary? We already appear to have used ExceptionAboutToReturn in the past. Can anyone remember its story? Maybe nested unwinding even has worked better in past Squeak versions before it has been removed? Hm ... I have the feeling that finding a better solution for this problem will keep occupying us for some more time. Maybe you have some other great ideas! :-) Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 16 13:43:52 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 16 Mar 2021 08:43:52 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615901797162-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> <1615901797162-0.post@n4.nabble.com> Message-ID: <1615902232566-0.post@n4.nabble.com> Hi Marcel, > Do not put a return "^" into an ensure block. Thanks for the statement. In this case, I have two follow-up questions for you: 1. So do you think #valueUninterruptably should be deprecated and disrecommended entirely? (Also note that in this method comment, Anthony Hannan already proposes a terminate message "to get the entire process unwound" ... This might be something similar to the new exception I considered in my previous post.) 2. Note that Jaromir has also found examples for unwind errors when abandoning an error that has been raised from an unwind context. While they also include control flow management, I think we cannot avoid such situations in general. Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From marcel.taeumel at hpi.de Tue Mar 16 13:47:03 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 16 Mar 2021 14:47:03 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: Hi Liam. I am happy to read that there is actual interest behind your initial question, which -- to be honest -- looked rather provocative to me. ;-) Sorry, if my previous answer did irritate you in some way. > Honestly, I hoped that some Squeak practitioners here might want to go > and engage themselves, or perhaps even suggest things I could counter > this negativity with. Well, countering a fundamentally negative attitude is in my experience not worth the effort if the topic-under-discussion may not even be relevant at all. Especially that thing about "malware" hints at a rather negative disposition toward people in general. Yet, I am always happy to answer open-minded questions about Squeak and its concepts. So, what aspects do you care for? Do you really have, say, hard real-time or security concerns? Or are you more interested in "augmenting human intellect" (see Douglas Engelbart) through a computational system? :-) Best, Marcel Am 16.03.2021 14:28:08 schrieb Liam Proven : On Tue, 16 Mar 2021 at 09:45, Marcel Taeumel wrote: > > Hi Liam. > > > [...] but a couple of the other points seem quite telling... or do they? > > Is this a typical low-effort "You tell me why I should care?"-situation? :-) :-( Well, no. I did present a talk advocating Smalltalk as a possible basis for a next-generation OS just last month and have discussed it at some length on this ML. But I am not in any way an expert in it. I tweeted about it, and now Twitter is showing me tweets about Smalltalk, including this one. Honestly, I hoped that some Squeak practitioners here might want to go and engage themselves, or perhaps even suggest things I could counter this negativity with. > Well, if you want to figure out whether your friend is right or wrong, you could try creating a non-trivial thing in Squeak. This involves getting to know the entire system, not just the Smalltalk language and standard library. You would have to figure out how Squeak's tools work and how to shorten the feedback cycle to the level you are most comfortable with. --- After that, you are qualified to ponder about what modern Web browsers (+ DOM/CSS/JavaScript) have achieved yet, and what they still miss. Maybe also include the motivation behind Docker and containerization in general. > > Just kidding. :-) Or am I? "Go and see for yourself" is sadly a very common rejoinder when asking programmers for information about programming languages, but it is pretty much never a helpful one. :-( -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 -------------- next part -------------- An HTML attachment was scrubbed... URL: From lproven at gmail.com Tue Mar 16 13:52:40 2021 From: lproven at gmail.com (Liam Proven) Date: Tue, 16 Mar 2021 14:52:40 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: On Tue, 16 Mar 2021 at 14:47, Marcel Taeumel wrote: > > Hi Liam. > > I am happy to read that there is actual interest behind your initial question, which -- to be honest -- looked rather provocative to me. ;-) Sorry, if my previous answer did irritate you in some way. It may have been, but it was _not my question_. > > Well, countering a fundamentally negative attitude is in my experience not worth the effort if the topic-under-discussion may not even be relevant at all. Especially that thing about "malware" hints at a rather negative disposition toward people in general. Yes and no. Up to a point I find Twitter useful for this: the shortness of posts mandates being terse and that tends to mean clear, quick, succinct. It prevents people from going on and on like a politician facing a difficult question. > Yet, I am always happy to answer open-minded questions about Squeak and its concepts. I don't know if you saw my talk, or read the script, or anything. If not, you might find it interesting, and then you would understand my position. The video is here: https://fosdem.org/2021/schedule/event/new_type_of_computer/ Transcript, slides, etc: https://liam-on-linux.livejournal.com/77065.html I am very much more on this side: > Or are you more interested in "augmenting human intellect" (see Douglas Engelbart) through a computational system? :-) -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 14:10:37 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 14:10:37 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: , Message-ID: Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von K K Subbu Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Tue Mar 16 15:04:16 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Tue, 16 Mar 2021 16:04:16 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: Hi Liam. > It may have been, but it was _not my question_. Oh, it sure was. You quoted something from Twitter added something like "Is he right?". That's definitely low effort. ;-) > [...] the shortness of posts mandates being terse and that tends to mean clear, quick, succinct [...] Ha! If anything, promotes laziness. Writing clear, concise, and correct thoughts takes a lot of effort. With more text, there is at least some chance that not-so-good writes may express themselves somehow. Without that, what's left is often superficial rant because there are not so many good writers out there. Just my two cents. :-) > I don't know if you saw my talk, or read the script, or anything. If > not, you might find it interesting, and then you would understand my > position. I will do that. Thanks for sharing. :-) Best, Marcel Am 16.03.2021 14:52:59 schrieb Liam Proven : On Tue, 16 Mar 2021 at 14:47, Marcel Taeumel wrote: > > Hi Liam. > > I am happy to read that there is actual interest behind your initial question, which -- to be honest -- looked rather provocative to me. ;-) Sorry, if my previous answer did irritate you in some way. It may have been, but it was _not my question_. > > Well, countering a fundamentally negative attitude is in my experience not worth the effort if the topic-under-discussion may not even be relevant at all. Especially that thing about "malware" hints at a rather negative disposition toward people in general. Yes and no. Up to a point I find Twitter useful for this: the shortness of posts mandates being terse and that tends to mean clear, quick, succinct. It prevents people from going on and on like a politician facing a difficult question. > Yet, I am always happy to answer open-minded questions about Squeak and its concepts. I don't know if you saw my talk, or read the script, or anything. If not, you might find it interesting, and then you would understand my position. The video is here: https://fosdem.org/2021/schedule/event/new_type_of_computer/ Transcript, slides, etc: https://liam-on-linux.livejournal.com/77065.html I am very much more on this side: > Or are you more interested in "augmenting human intellect" (see Douglas Engelbart) through a computational system? :-) -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 15:49:52 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 15:49:52 +0000 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: , Message-ID: Side note: > > [...] the shortness of posts mandates being terse and that tends to mean clear, quick, succinct [...] > > Ha! If anything, promotes laziness. Writing clear, concise, and correct thoughts takes a lot of effort. Being brief takes a lot of effort, too, I can tell you ... ;-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 16. März 2021 16:04:16 An: squeak-dev Betreff: Re: [squeak-dev] Twitter Smalltalk discussion that may interest folk here Hi Liam. > It may have been, but it was _not my question_. Oh, it sure was. You quoted something from Twitter added something like "Is he right?". That's definitely low effort. ;-) > [...] the shortness of posts mandates being terse and that tends to mean clear, quick, succinct [...] Ha! If anything, promotes laziness. Writing clear, concise, and correct thoughts takes a lot of effort. With more text, there is at least some chance that not-so-good writes may express themselves somehow. Without that, what's left is often superficial rant because there are not so many good writers out there. Just my two cents. :-) > I don't know if you saw my talk, or read the script, or anything. If > not, you might find it interesting, and then you would understand my > position. I will do that. Thanks for sharing. :-) Best, Marcel Am 16.03.2021 14:52:59 schrieb Liam Proven : On Tue, 16 Mar 2021 at 14:47, Marcel Taeumel wrote: > > Hi Liam. > > I am happy to read that there is actual interest behind your initial question, which -- to be honest -- looked rather provocative to me. ;-) Sorry, if my previous answer did irritate you in some way. It may have been, but it was _not my question_. > > Well, countering a fundamentally negative attitude is in my experience not worth the effort if the topic-under-discussion may not even be relevant at all. Especially that thing about "malware" hints at a rather negative disposition toward people in general. Yes and no. Up to a point I find Twitter useful for this: the shortness of posts mandates being terse and that tends to mean clear, quick, succinct. It prevents people from going on and on like a politician facing a difficult question. > Yet, I am always happy to answer open-minded questions about Squeak and its concepts. I don't know if you saw my talk, or read the script, or anything. If not, you might find it interesting, and then you would understand my position. The video is here: https://fosdem.org/2021/schedule/event/new_type_of_computer/ Transcript, slides, etc: https://liam-on-linux.livejournal.com/77065.html I am very much more on this side: > Or are you more interested in "augmenting human intellect" (see Douglas Engelbart) through a computational system? :-) -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 -------------- next part -------------- An HTML attachment was scrubbed... URL: From lproven at gmail.com Tue Mar 16 15:55:35 2021 From: lproven at gmail.com (Liam Proven) Date: Tue, 16 Mar 2021 16:55:35 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: On Tue, 16 Mar 2021 at 16:49, Thiede, Christoph wrote: > > Side note: > > Being brief takes a lot of effort, too, I can tell you ... ;-) "Je n’ai fait celle-ci plus longue que parce que je n’ai pas eu le loisir de la faire plus courte," as Blaise Pascal said. Mark Twain rendered it as "If I had more time, I would have written a shorter letter." But you get used to it... -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 16 16:29:39 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 16 Mar 2021 11:29:39 -0500 (CDT) Subject: [squeak-dev] Refactoring #terminate to get rid of 'cannot return' errors etc. In-Reply-To: <1615708691721-0.post@n4.nabble.com> References: <1615708691721-0.post@n4.nabble.com> Message-ID: <1615912179202-0.post@n4.nabble.com> Hi Jaromir, I'm not an expert in this domain but maybe I can give my two cents anyway: So first of all, you mentioned two motivations for your change: 1. Make terminated processes resumable 2. Clean up logic for testing termination For 1: This is unorthodox thought because, in my view, a terminated process has reached the end of its life cycle and does not need to be resumed again. Can you give a concrete example where this would be useful to you? Why wouldn't you create a new process instead in this situation? Why wouldn't you just suspend the process? Why wouldn't you just manipulate its suspendedContext manually? :-) For 2: Cleaning up decades-old code is an honorable plan and might get neglected too open in some areas. But if I understand you correctly, your proposal would not directly allow us to remove the current #isTerminated logic but only extend it, right? Because there could still be processes not using the new #terminated marker and thus requiring us to keep the old mechanisms. If this is correct, you basically propose to introduce an alternative approach that needs to coexist with the existing one. I am not sure whether this is really a desirable aim ... On the other hand, #newProcess looks nicer now. Just some thoughts without a final judgment (which I'm not qualified to pass anyway). :-) And one small footnote: > >>>> ctxt setSender: nil receiver: self method: (Process>>#terminated) arguments: {} I don't think we should consider these variables of a stack frame as mutable fields. I'm not sure how the VM thinks about (see Eliot's description of context marriage in [1]) and there might also be some entries in the local stack of the context not being cleaned up. Wouldn't it be possible to replace the context instance instead? See Context>>#activateMethod:withArgs:receiver:class: or your own approach in #newProcess. Best, Christoph [1] http://forum.world.st/Two-new-curious-Context-primitive-questions-tp5125779p5125783.html ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 16:52:23 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 16:52:23 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: , , Message-ID: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von K K Subbu Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -------------- next part -------------- An HTML attachment was scrubbed... URL: From lecteur at zogotounga.net Tue Mar 16 17:40:45 2021 From: lecteur at zogotounga.net (=?UTF-8?Q?St=c3=a9phane_Rollandin?=) Date: Tue, 16 Mar 2021 18:40:45 +0100 Subject: [squeak-dev] [OT] some Squeak music Message-ID: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> Hello all, I just finished a new piece of music entirely composed and performed within a muO image - the audio is recorded from virtual instruments fed a live MIDI output stream. This is done with a technology that does not exists elsewhere. I know it is not the place to post (weird) music, but in the broader context of the discussion about the death of Smalltalk, I felt inclined to illustrate how for some of us it is very much alive and singing. Here it is: http://www.zogotounga.net/zik/Pentaxoyothol.ogg Stef From tim at rowledge.org Tue Mar 16 18:54:08 2021 From: tim at rowledge.org (tim Rowledge) Date: Tue, 16 Mar 2021 11:54:08 -0700 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> Message-ID: > On 2021-03-16, at 10:40 AM, Stéphane Rollandin wrote: > > http://www.zogotounga.net/zik/Pentaxoyothol.ogg It's not my kind of music (I'm a Mike Oldfield/Filk/SteamPunk type) but it always impresses the hell out of me what you can make with your system. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim The gains I make don't make me a hero; all the work I do is just to get back to Zero From tim at rowledge.org Tue Mar 16 19:09:01 2021 From: tim at rowledge.org (tim Rowledge) Date: Tue, 16 Mar 2021 12:09:01 -0700 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: Liam, our problem here is at least in part one of weariness. If you were to read back in the mail list archives you'd find ... many, perhaps hundreds?... of times when somebody has asked us collectively to explain "why Smalltalk?" Sometimes it is genuinely curious people that want to understand, that listen and then join the collective, err, I mean the team. Often, so very often, it is somebody wanting a fight over some crypto-religious point. Bizarrely, quite a lot of people seem to be threatened by the idea of a not-dead-text-in-files world. A looong time ago we suffered a prolonged attack of "it must be changed to be just like Visual BASIC or it will die!!!" demands. Dan Ingalls even responded by making an alternate syntax setup that allowed code to be written and presented as a BASIC-like text. We have long suffered from drive-by idiocy telling us that an interpreted language with all that wasteful trash of structure and garbage collection and message sending cannot possibly work and will always be slow and nobody will ever understand it and you can't write applications in it and real programmers use XXXXX (where XXXXX is flavour of the month on some gitidiot/slashdot type site) and by the way you people have bad breath. Presenting facts does essentially nothing to stop this. If you want to see some decent quality Smalltalk evangelism and explanation, try quora.com and look for articles by people like 'Mr Smalltalk', Richard Eng. He's had to pretty much retire from this effort for medical reasons but he put a *lot* of effort into presenting things. Obviously, never look at any other parts of Quora - the site that is an existence proof that not only are there, in fact, stupid questions but that there is a near infinite supply of people wanting to ask them again and again and again. The couple of tweets you pointed to seem to me to be excellent examples of people that have no interest at all in understanding or learning anything new. It's just another case of "somebody is wrong on the internet" and I fear most of us here are a bit worn out with that. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Hard work pays off in the future. Laziness pays off now. From eliot.miranda at gmail.com Tue Mar 16 19:43:41 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Tue, 16 Mar 2021 12:43:41 -0700 Subject: [squeak-dev] #testBecomeForward fails when simulated in a rush In-Reply-To: <5f2b013b71ac40009143e860a3fd7769@student.hpi.uni-potsdam.de> References: <5f2b013b71ac40009143e860a3fd7769@student.hpi.uni-potsdam.de> Message-ID: Hi Christoph, On Sun, Mar 14, 2021 at 8:48 AM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Hi all, > > > it's Sunday afternoon (at least in my timezone :D) and here's an > interesting weekend issue for you, maybe even a bug in the VM: > > > p := [ObjectTest new testBecomeForward] newProcess. > p runUntil: [:c | c isDead]. > > In my fresh trunk image, this expression always fails, i.e. a TestFailure > is raised from the second assertion in the test, pt3 == pt2. > > However, when running the test normally, i.e. executing the first block > without simulation, the test passes as expected. > Also, when I try to debug the simulation, the test passes again. > > But I even inserted a halt around the (pt3 == pt2) and could see that it > actually evaluated to false. > > > And when I change the expression like this, it suddenly passes: > > > p := [ObjectTest new testBecomeForward] newProcess. > p runUntil: [:c | Smalltalk garbageCollect. c isDead]. > > What is this? Does the VM require some kind of memory sweep before the > object identity consistency is restored again? To me, this looks pretty > suspicious at least. > Thank you. You've found a bug in the interpreted version of primitive 110. It read primitiveIdentical "is the receiver/first argument the same object as the (last) argument?. pop argumentCount because this can be used as a mirror primitive." | thisObject otherObject | otherObject := self stackValue: 1. thisObject := self stackTop. ((objectMemory isOopForwarded: otherObject) or: [argumentCount > 1 and: [objectMemory isOopForwarded: thisObject]]) ifTrue: [self primitiveFailFor: PrimErrBadArgument] ifFalse: [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] but this is the wrong way around. It should read primitiveIdentical "is the receiver/first argument the same object as the (last) argument?. pop argumentCount because this can be used as a mirror primitive." | thisObject otherObject | thisObject := self stackValue: 1. otherObject := self stackTop. ((objectMemory isOopForwarded: otherObject) or: [argumentCount > 1 and: [objectMemory isOopForwarded: thisObject]]) ifTrue: [self primitiveFailFor: PrimErrBadArgument] ifFalse: [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] The invariant on invoking a primitive is that the receiver is unforwarded. This is because it being the receiver of the message, the message send machinery ensures it is not forwarded (if it was, the cached message send logic would fail, and the slow lookup path checks for a forwarded receiver, unforwarding and repeating the send if so). But primitive arguments could be forwarded. So primitiveIdentical must check for a potentially forwarded argument. Stupidly I had written this carelessly and had not got the variable names the right way round and hence was checking if the receiver was forwarded, not the argument. > In SqueakJS, I cannot reproduce the issue, i.e., since > https://github.com/codefrau/SqueakJS/pull/117, #testBecomeForward never > fails. > SqueakJS doesn't use transparent forwarding. You'll also find that it won't fail in a pre-Spur image. > Best, > > Christoph > _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From vanessa at codefrau.net Tue Mar 16 20:59:05 2021 From: vanessa at codefrau.net (Vanessa Freudenberg) Date: Tue, 16 Mar 2021 13:59:05 -0700 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> Message-ID: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > One more question: Do you know where I can find the Smalltalk > implementation of worlds? Is there any at all? The abstract in ResearchGate > mentions this but is not addressed in the paper ... > Well luckily one of the authors is still on this list ... Looks really interesting and useful! Vanessa > Best, > > Christoph > > ------------------------------ > *Von:* Thiede, Christoph > *Gesendet:* Dienstag, 16. März 2021 15:10:37 > *An:* squeak-dev at lists.squeakfoundation.org > *Betreff:* AW: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > > Hi Subbu, thanks a lot for your thoughts! :-) > > > > I am not sure if you have read Warth's research at VPRI > > > No, I have not. Looks very interesting, I will read this! > > The only literature I had found on this (I have to admit that I did not > spend much time on research) was this one: > https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a > number of problems but does not come up with a simulation solution, so it > would exclusively lock your image, I guess. > > > I expect efficiency to improve if VM (e.g. object memory) exposes primitives > for object spaces with copy-on-write and white-outs (for objects > finalized in child space but not in parent). A sandbox could carve out an > object space to hold modified/deleted objects and then either commit to > parent or dispose it off on close. ObjectMemory already has support for > multiple spaces (e.g. old and young). It needs to be exposed, with lots > of care, to ST-side code. > > Yeah, integrating the sandbox partially into the VM would make things > faster, of course ... I haven't made any attempts in this direction for two > reasons: First because I, honestly, still did not find the time for getting > started with VMMaker, and second because while I know that the VM is > written in a Smalltalk dialect as well, it hurts me a bit that it lacks the > liveness of manipulating everything from within the running image. By the > way, is there already some research about unioning these two worlds in > order to reprogram the VM from within the image that is running in it? I > would love this. > > What are white-outs? I could not find any reference on this. > > > Handling primitives, particularly those that involve physical i/o, is a difficult > problem. This is typically solved by using virtualization and double > buffering (e.g. display or input). It is ok to work with non-volatile > state variables for the first cut and then introduce virtualization for > transactional access. > > Actually, my current Sandbox approach does not even intend to "commit" > changes back to the rest of the image (rather to work like a Docker > container in small). Thus my goal would rather be to virtualize all > physical operations but keeping the effects back from the real physical > devices. For filesystem accesses, for example, I thought about redirecting > all write operations to a copy of the files in a special folder ... Not > sure how far this approach would work well, though. > > For some I/O primitives, however, virtualization is rather easy. For > example, when writing on the global Display, you can simply copy this > object like any other object into your sandbox space/world. However, other > primitives, such as from the FilePlugin, operate on state is managed > outside of the image ... > > Best, > Christoph > > ------------------------------ > *Von:* Squeak-dev im > Auftrag von K K Subbu > *Gesendet:* Dienstag, 16. März 2021 14:21:16 > *An:* squeak-dev at lists.squeakfoundation.org > *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > > On 16/03/21 4:51 pm, Thiede, Christoph wrote: > > Hi all! :-) > > > > > > I'm very excited to finally share my new project with you today, which I > > call *SimulationStudio* and have made available on GitHub under [1]. Its > > primary function is to provide an inheritable > > *SimulationContext* subclass of Context that makes it easy to simulate > > entire call trees while customizing the execution or installing custom > > hooks for various tracing and measurement purposes. Another > > accomplishment is the *Sandbox* which allows you to run arbitrary > > Smalltalk code in an isolated environment, separating any side effects > > that occur during the simulation from the rest of the image. > > This is an amazing development! > > I am not sure if you have read Warth's research at VPRI: > > World: Controlling the Scope of Side Effects by A Warth et. all, > > > > https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects > > Worlds is like your Sandbox. It also had a commit method to propagate > state changes from the child to the parent. This is useful when a method > modifies multiple state variables subject to strong invariants. A method > may open a World, make changes and then verify invariants are preserved > before committing the changes and closing the World. > > > *Limitations and challenges* > > > > Well, first of all ... *performance.* :-) Some recent measurements that > > I have run have shown that the simulator reaches about 0.1 percent (sic) > > of the speed of the VM executor, depending on the domain and the > > distribution of bytecode operations. > > I expect efficiency to improve if VM (e.g. object memory) exposes > primitives for object spaces with copy-on-write and white-outs (for > objects finalized in child space but not in parent). A sandbox could > carve out an object space to hold modified/deleted objects and then > either commit to parent or dispose it off on close. ObjectMemory already > has support for multiple spaces (e.g. old and young). It needs to be > exposed, with lots of care, to ST-side code. > > > Another challenge is the *handling of primitive operations* during the > > sandbox execution. > > Handling primitives, particularly those that involve physical i/o, is a > difficult problem. This is typically solved by using virtualization and > double buffering (e.g. display or input). It is ok to work with > non-volatile state variables for the first cut and then introduce > virtualization for transactional access. > > Regards .. Subbu > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lecteur at zogotounga.net Tue Mar 16 21:22:48 2021 From: lecteur at zogotounga.net (=?UTF-8?Q?St=c3=a9phane_Rollandin?=) Date: Tue, 16 Mar 2021 22:22:48 +0100 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> Message-ID: <7f9091b8-cedb-b4f1-a7b9-e32d1729b55e@zogotounga.net> >> http://www.zogotounga.net/zik/Pentaxoyothol.ogg > > It's not my kind of music (I'm a Mike Oldfield/Filk/SteamPunk type) but it always impresses the hell out of me what you can make with your system. Yes, I realize that my own music is probably not the best one to use for promoting the system... But muO is not wired to my specific taste and can handle pretty much anything. Its interface (or lack of) and the current state of its documentation would certainly be a problem for another composer, though. At the moment muO is very much a big bag of specialized lego bricks, that I assemble differently for each piece I do. Now if somebody was seriously interested, I would definitely be willing to provide customized GUIs and a taylored workflow - it's only a matter of building a screening facade exposing some of the existing raw functionality. I did exactly that with Boadebui which is a clone of Boscal Ceoil: http://www.zogotounga.net/comp/boadebui.htm https://boscaceoil.net/ Stef From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 22:18:44 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 22:18:44 +0000 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <7f9091b8-cedb-b4f1-a7b9-e32d1729b55e@zogotounga.net> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> , <7f9091b8-cedb-b4f1-a7b9-e32d1729b55e@zogotounga.net> Message-ID: <5b3bf865fd1649718c7cbcf40916b45f@student.hpi.uni-potsdam.de> Nice song, I did not know the genre, but I like it. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Stéphane Rollandin Gesendet: Dienstag, 16. März 2021 22:22:48 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [OT] some Squeak music >> http://www.zogotounga.net/zik/Pentaxoyothol.ogg > > It's not my kind of music (I'm a Mike Oldfield/Filk/SteamPunk type) but it always impresses the hell out of me what you can make with your system. Yes, I realize that my own music is probably not the best one to use for promoting the system... But muO is not wired to my specific taste and can handle pretty much anything. Its interface (or lack of) and the current state of its documentation would certainly be a problem for another composer, though. At the moment muO is very much a big bag of specialized lego bricks, that I assemble differently for each piece I do. Now if somebody was seriously interested, I would definitely be willing to provide customized GUIs and a taylored workflow - it's only a matter of building a screening facade exposing some of the existing raw functionality. I did exactly that with Boadebui which is a clone of Boscal Ceoil: http://www.zogotounga.net/comp/boadebui.htm https://boscaceoil.net/ Stef -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 22:23:23 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 22:23:23 +0000 Subject: [squeak-dev] #testBecomeForward fails when simulated in a rush In-Reply-To: References: <5f2b013b71ac40009143e860a3fd7769@student.hpi.uni-potsdam.de>, Message-ID: <95ef19eb17b04cc8919c770e957e6672@student.hpi.uni-potsdam.de> Hi Eliot, thanks for fixing it! I still don't understand why the bug only occurred during simulation, but glad you were able to find the cause. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Eliot Miranda Gesendet: Dienstag, 16. März 2021 20:43:41 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] #testBecomeForward fails when simulated in a rush Hi Christoph, On Sun, Mar 14, 2021 at 8:48 AM Thiede, Christoph > wrote: Hi all, it's Sunday afternoon (at least in my timezone :D) and here's an interesting weekend issue for you, maybe even a bug in the VM: p := [ObjectTest new testBecomeForward] newProcess. p runUntil: [:c | c isDead]. In my fresh trunk image, this expression always fails, i.e. a TestFailure is raised from the second assertion in the test, pt3 == pt2. However, when running the test normally, i.e. executing the first block without simulation, the test passes as expected. Also, when I try to debug the simulation, the test passes again. But I even inserted a halt around the (pt3 == pt2) and could see that it actually evaluated to false. And when I change the expression like this, it suddenly passes: p := [ObjectTest new testBecomeForward] newProcess. p runUntil: [:c | Smalltalk garbageCollect. c isDead]. What is this? Does the VM require some kind of memory sweep before the object identity consistency is restored again? To me, this looks pretty suspicious at least. Thank you. You've found a bug in the interpreted version of primitive 110. It read primitiveIdentical "is the receiver/first argument the same object as the (last) argument?. pop argumentCount because this can be used as a mirror primitive." | thisObject otherObject | otherObject := self stackValue: 1. thisObject := self stackTop. ((objectMemory isOopForwarded: otherObject) or: [argumentCount > 1 and: [objectMemory isOopForwarded: thisObject]]) ifTrue: [self primitiveFailFor: PrimErrBadArgument] ifFalse: [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] but this is the wrong way around. It should read primitiveIdentical "is the receiver/first argument the same object as the (last) argument?. pop argumentCount because this can be used as a mirror primitive." | thisObject otherObject | thisObject := self stackValue: 1. otherObject := self stackTop. ((objectMemory isOopForwarded: otherObject) or: [argumentCount > 1 and: [objectMemory isOopForwarded: thisObject]]) ifTrue: [self primitiveFailFor: PrimErrBadArgument] ifFalse: [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] The invariant on invoking a primitive is that the receiver is unforwarded. This is because it being the receiver of the message, the message send machinery ensures it is not forwarded (if it was, the cached message send logic would fail, and the slow lookup path checks for a forwarded receiver, unforwarding and repeating the send if so). But primitive arguments could be forwarded. So primitiveIdentical must check for a potentially forwarded argument. Stupidly I had written this carelessly and had not got the variable names the right way round and hence was checking if the receiver was forwarded, not the argument. In SqueakJS, I cannot reproduce the issue, i.e., since https://github.com/codefrau/SqueakJS/pull/117, #testBecomeForward never fails. SqueakJS doesn't use transparent forwarding. You'll also find that it won't fail in a pre-Spur image. Best, Christoph _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From Yoshiki.Ohshima at acm.org Tue Mar 16 22:48:52 2021 From: Yoshiki.Ohshima at acm.org (Yoshiki Ohshima) Date: Tue, 16 Mar 2021 15:48:52 -0700 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> Message-ID: Hi! We still maintain the packages from VPRI. Looking at the directory, we have quite a few versions of Worlds. So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg wrote: > On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > >> One more question: Do you know where I can find the Smalltalk >> implementation of worlds? Is there any at all? The abstract in ResearchGate >> mentions this but is not addressed in the paper ... >> > Well luckily one of the authors is still on this list ... > > Looks really interesting and useful! > > Vanessa > >> Best, >> >> Christoph >> >> ------------------------------ >> *Von:* Thiede, Christoph >> *Gesendet:* Dienstag, 16. März 2021 15:10:37 >> *An:* squeak-dev at lists.squeakfoundation.org >> *Betreff:* AW: [squeak-dev] [ANN] SimulationStudio and sandboxed >> execution for Squeak >> >> >> Hi Subbu, thanks a lot for your thoughts! :-) >> >> >> > I am not sure if you have read Warth's research at VPRI >> >> >> No, I have not. Looks very interesting, I will read this! >> >> The only literature I had found on this (I have to admit that I did not >> spend much time on research) was this one: >> https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a >> number of problems but does not come up with a simulation solution, so it >> would exclusively lock your image, I guess. >> >> > I expect efficiency to improve if VM (e.g. object memory) exposes primitives >> for object spaces with copy-on-write and white-outs (for objects >> finalized in child space but not in parent). A sandbox could carve out >> an object space to hold modified/deleted objects and then either commit >> to parent or dispose it off on close. ObjectMemory already has support >> for multiple spaces (e.g. old and young). It needs to be exposed, with >> lots of care, to ST-side code. >> >> Yeah, integrating the sandbox partially into the VM would make things >> faster, of course ... I haven't made any attempts in this direction for two >> reasons: First because I, honestly, still did not find the time for getting >> started with VMMaker, and second because while I know that the VM is >> written in a Smalltalk dialect as well, it hurts me a bit that it lacks the >> liveness of manipulating everything from within the running image. By the >> way, is there already some research about unioning these two worlds in >> order to reprogram the VM from within the image that is running in it? I >> would love this. >> >> What are white-outs? I could not find any reference on this. >> >> > Handling primitives, particularly those that involve physical i/o, is >> a difficult problem. This is typically solved by using virtualization >> and double buffering (e.g. display or input). It is ok to work with non-volatile >> state variables for the first cut and then introduce virtualization for >> transactional access. >> >> Actually, my current Sandbox approach does not even intend to "commit" >> changes back to the rest of the image (rather to work like a Docker >> container in small). Thus my goal would rather be to virtualize all >> physical operations but keeping the effects back from the real physical >> devices. For filesystem accesses, for example, I thought about redirecting >> all write operations to a copy of the files in a special folder ... Not >> sure how far this approach would work well, though. >> >> For some I/O primitives, however, virtualization is rather easy. For >> example, when writing on the global Display, you can simply copy this >> object like any other object into your sandbox space/world. However, other >> primitives, such as from the FilePlugin, operate on state is managed >> outside of the image ... >> >> Best, >> Christoph >> >> ------------------------------ >> *Von:* Squeak-dev im >> Auftrag von K K Subbu >> *Gesendet:* Dienstag, 16. März 2021 14:21:16 >> *An:* squeak-dev at lists.squeakfoundation.org >> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >> execution for Squeak >> >> >> On 16/03/21 4:51 pm, Thiede, Christoph wrote: >> > Hi all! :-) >> > >> > >> > I'm very excited to finally share my new project with you today, which >> I >> > call *SimulationStudio* and have made available on GitHub under [1]. >> Its >> > primary function is to provide an inheritable >> > *SimulationContext* subclass of Context that makes it easy to simulate >> > entire call trees while customizing the execution or installing custom >> > hooks for various tracing and measurement purposes. Another >> > accomplishment is the *Sandbox* which allows you to run arbitrary >> > Smalltalk code in an isolated environment, separating any side effects >> > that occur during the simulation from the rest of the image. >> >> This is an amazing development! >> >> I am not sure if you have read Warth's research at VPRI: >> >> World: Controlling the Scope of Side Effects by A Warth et. all, >> >> >> >> https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects >> >> Worlds is like your Sandbox. It also had a commit method to propagate >> state changes from the child to the parent. This is useful when a method >> modifies multiple state variables subject to strong invariants. A method >> may open a World, make changes and then verify invariants are preserved >> before committing the changes and closing the World. >> >> > *Limitations and challenges* >> > >> > Well, first of all ... *performance.* :-) Some recent measurements that >> > I have run have shown that the simulator reaches about 0.1 percent >> (sic) >> > of the speed of the VM executor, depending on the domain and the >> > distribution of bytecode operations. >> >> I expect efficiency to improve if VM (e.g. object memory) exposes >> primitives for object spaces with copy-on-write and white-outs (for >> objects finalized in child space but not in parent). A sandbox could >> carve out an object space to hold modified/deleted objects and then >> either commit to parent or dispose it off on close. ObjectMemory already >> has support for multiple spaces (e.g. old and young). It needs to be >> exposed, with lots of care, to ST-side code. >> >> > Another challenge is the *handling of primitive operations* during the >> > sandbox execution. >> >> Handling primitives, particularly those that involve physical i/o, is a >> difficult problem. This is typically solved by using virtualization and >> double buffering (e.g. display or input). It is ok to work with >> non-volatile state variables for the first cut and then introduce >> virtualization for transactional access. >> >> Regards .. Subbu >> >> >> -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Tue Mar 16 22:52:15 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 16 Mar 2021 22:52:15 0000 Subject: [squeak-dev] The Inbox: KernelTests-jar.396.mcz Message-ID: A new version of KernelTests was added to project The Inbox: http://source.squeak.org/inbox/KernelTests-jar.396.mcz ==================== Summary ==================== Name: KernelTests-jar.396 Author: jar Time: 16 March 2021, 11:52:12.69619 pm UUID: 35e3c78b-a504-c544-aa0c-f652405ba417 Ancestors: KernelTests-mt.394 Complementing Kernel-jar.1381.mcz It tests that a process is terminated when it reaches the last instruction of the bottom context for methods other than Process>>#terminate; this test would fail with the previous version of isTerminated. =============== Diff against KernelTests-mt.394 =============== Item was added: + ----- Method: ProcessTest>>terminated (in category 'support') ----- + terminated + "supports testProcessStateTests2" + + ^self suspend. + ! Item was added: + ----- Method: ProcessTest>>testProcessStateTests2 (in category 'tests') ----- + testProcessStateTests2 + "I test that a process is terminated when it reaches the last instruction + of the bottom context for methods other than Process>>#terminate; + this test would fail with the version of isTerminated before 3/11/2021." + + | bottomContext newProcess | + + newProcess := Process new. + bottomContext := Context + sender: nil + receiver: newProcess + method: (ProcessTest>>#terminated) + arguments: {}. + newProcess suspendedContext: ([] asContextWithSender: bottomContext). + newProcess priority: Processor activePriority. + + self deny: newProcess isTerminated. + newProcess terminate. + self assert: newProcess isTerminated. + ! From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 22:55:24 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 22:55:24 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> , Message-ID: <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi! We still maintain the packages from VPRI. Looking at the directory, we have quite a few versions of Worlds. So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg > wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph > wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ... Looks really interesting and useful! Vanessa Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von K K Subbu > Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Tue Mar 16 22:56:57 2021 From: m at jaromir.net (Jaromir Matas) Date: Tue, 16 Mar 2021 17:56:57 -0500 (CDT) Subject: [squeak-dev] The Inbox: Kernel-jar.1381.mcz In-Reply-To: <1615898081632-0.post@n4.nabble.com> References: <1615898081632-0.post@n4.nabble.com> Message-ID: <1615935417914-0.post@n4.nabble.com> > If you want to act in an exemplary manner, it would be > great if you could submit a test case for this in ProcessTest in a new > inbox > version by using the example you mentioned in [1]. :-) Submitted. PS: The simple example in [1] didn't work as a test so I created a no-nonsensical bottom context for the test manually. Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 22:58:44 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 22:58:44 +0000 Subject: [squeak-dev] The Inbox: Kernel-jar.1381.mcz In-Reply-To: <1615935417914-0.post@n4.nabble.com> References: <1615898081632-0.post@n4.nabble.com>,<1615935417914-0.post@n4.nabble.com> Message-ID: LGTM :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Dienstag, 16. März 2021 23:56:57 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] The Inbox: Kernel-jar.1381.mcz > If you want to act in an exemplary manner, it would be > great if you could submit a test case for this in ProcessTest in a new > inbox > version by using the example you mentioned in [1]. :-) Submitted. PS: The simple example in [1] didn't work as a test so I created a no-nonsensical bottom context for the test manually. Thanks, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Tue Mar 16 23:05:24 2021 From: m at jaromir.net (Jaromir Matas) Date: Tue, 16 Mar 2021 18:05:24 -0500 (CDT) Subject: [squeak-dev] Refactoring #terminate to get rid of 'cannot return' errors etc. In-Reply-To: <1615912179202-0.post@n4.nabble.com> References: <1615708691721-0.post@n4.nabble.com> <1615912179202-0.post@n4.nabble.com> Message-ID: <1615935924805-0.post@n4.nabble.com> Hi Christoph, Many thanks for your inspiring questions! I really appreciate that. My main motivations (apart from curiosity and learning): 1. Avoid 'cannot return' errors - by no means I want "resumable" terminated processes ;) I just thought resuming them should be harmless; it could save checking whether a process is terminated to avoid errors. Real life examples? I'm thinking parallel computing where one process can terminate while another one running in parallel might still want to resume it assuming or hoping it is only suspended (without an explicit check that would raise an exception). Just a thought... Resuming a terminated process in this scenario wouldn't really "resume" it but only suspend it again to avoid the 'cannot return' error. 2. Readability of the code (newProcess's logic isn't easy to decode) 3. Easy way to spot a terminated process while debugging :) (suspendedContext = Process>>#terminated) > Clean up logic for testing termination. [...] Because there could still be > processes not using the new #terminated marker and thus requiring us to > keep the old mechanisms. Yes, you're right some processes might still be created the alternative way ("manually") as long as the alternative way is available but that doesn't mean extending the current isTerminated logic - only keeping it the same. I don't even think it can be simplified any further beyond these conditions: a) process is defunct / dead, or b) process is parked in #terminated, or c) process is at its last instruction But yes, my proposal doesn't decrease complexity, only - I hope - increases readability. I wouldn't dare to introduce anything in addition to the existing that would increase complexity. I'm convinced the core code must be kept at minimum complexity and maximum readability :) > I don't think we should consider these variables of a stack frame as > mutable fields. [...] Wouldn't it be possible to replace the context > instance instead? That's an interesting idea... Thanks! Widowed, divorced or single should be ok so only married ones can have a problem :) I can't answer this one but at least in my image it works. However, replacing: ctxt setSender: nil receiver: self method: (Process>>#terminated) arguments: {}. with: ctxt := Context sender: nil receiver: self method: (Process>>#terminated) arguments: {} doesn't update the stack frame because nothing happens, however the #setSender apparently must update the stack frame because it seems to work; I guess it's because it manipulates an existing spouse (context) instead of replacing her with a brand new. Once married the stack frames cannot replace their spouse contexts after all ;) However I'm not an expert in these matters. I'll explore... Again, thanks for your feedback, best regards, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From lecteur at zogotounga.net Tue Mar 16 23:20:47 2021 From: lecteur at zogotounga.net (=?UTF-8?Q?St=c3=a9phane_Rollandin?=) Date: Wed, 17 Mar 2021 00:20:47 +0100 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <5b3bf865fd1649718c7cbcf40916b45f@student.hpi.uni-potsdam.de> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> <7f9091b8-cedb-b4f1-a7b9-e32d1729b55e@zogotounga.net> <5b3bf865fd1649718c7cbcf40916b45f@student.hpi.uni-potsdam.de> Message-ID: <9d1c5c70-e748-8aad-ce13-af072cd322bc@zogotounga.net> > Nice song, I did not know the genre, but I like it. :-) I don't know the genre either :) Stef From Yoshiki.Ohshima at acm.org Tue Mar 16 23:20:53 2021 From: Yoshiki.Ohshima at acm.org (Yoshiki Ohshima) Date: Tue, 16 Mar 2021 16:20:53 -0700 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> Message-ID: W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory. The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Thanks! Unfortunately, it's referring to a WCompiler which apparently is > not part of the mcz file ... > > > Best, > > Christoph > > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Yoshiki Ohshima > *Gesendet:* Dienstag, 16. März 2021 23:48:52 > *An:* Vanessa Freudenberg > *Cc:* The general-purpose Squeak developers list > *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > Hi! > > We still maintain the packages from VPRI. Looking at the directory, we > have quite a few versions of Worlds. So there is a chance that it does > something. > > http://tinlizzie.org/updates/exploratory/packages/ > > On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg > wrote: > >> On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph < >> Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: >> >>> One more question: Do you know where I can find the Smalltalk >>> implementation of worlds? Is there any at all? The abstract in ResearchGate >>> mentions this but is not addressed in the paper ... >>> >> Well luckily one of the authors is still on this list ... >> >> Looks really interesting and useful! >> >> Vanessa >> >>> Best, >>> >>> Christoph >>> >>> ------------------------------ >>> *Von:* Thiede, Christoph >>> *Gesendet:* Dienstag, 16. März 2021 15:10:37 >>> *An:* squeak-dev at lists.squeakfoundation.org >>> *Betreff:* AW: [squeak-dev] [ANN] SimulationStudio and sandboxed >>> execution for Squeak >>> >>> >>> Hi Subbu, thanks a lot for your thoughts! :-) >>> >>> >>> > I am not sure if you have read Warth's research at VPRI >>> >>> >>> No, I have not. Looks very interesting, I will read this! >>> >>> The only literature I had found on this (I have to admit that I did not >>> spend much time on research) was this one: >>> https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a >>> number of problems but does not come up with a simulation solution, so it >>> would exclusively lock your image, I guess. >>> >>> > I expect efficiency to improve if VM (e.g. object memory) exposes primitives >>> for object spaces with copy-on-write and white-outs (for objects >>> finalized in child space but not in parent). A sandbox could carve out >>> an object space to hold modified/deleted objects and then either commit >>> to parent or dispose it off on close. ObjectMemory already has support >>> for multiple spaces (e.g. old and young). It needs to be exposed, with >>> lots of care, to ST-side code. >>> >>> Yeah, integrating the sandbox partially into the VM would make things >>> faster, of course ... I haven't made any attempts in this direction for two >>> reasons: First because I, honestly, still did not find the time for getting >>> started with VMMaker, and second because while I know that the VM is >>> written in a Smalltalk dialect as well, it hurts me a bit that it lacks the >>> liveness of manipulating everything from within the running image. By the >>> way, is there already some research about unioning these two worlds in >>> order to reprogram the VM from within the image that is running in it? I >>> would love this. >>> >>> What are white-outs? I could not find any reference on this. >>> >>> > Handling primitives, particularly those that involve physical i/o, is >>> a difficult problem. This is typically solved by using virtualization >>> and double buffering (e.g. display or input). It is ok to work with non-volatile >>> state variables for the first cut and then introduce virtualization for >>> transactional access. >>> >>> Actually, my current Sandbox approach does not even intend to "commit" >>> changes back to the rest of the image (rather to work like a Docker >>> container in small). Thus my goal would rather be to virtualize all >>> physical operations but keeping the effects back from the real physical >>> devices. For filesystem accesses, for example, I thought about redirecting >>> all write operations to a copy of the files in a special folder ... Not >>> sure how far this approach would work well, though. >>> >>> For some I/O primitives, however, virtualization is rather easy. For >>> example, when writing on the global Display, you can simply copy this >>> object like any other object into your sandbox space/world. However, other >>> primitives, such as from the FilePlugin, operate on state is managed >>> outside of the image ... >>> >>> Best, >>> Christoph >>> >>> ------------------------------ >>> *Von:* Squeak-dev im >>> Auftrag von K K Subbu >>> *Gesendet:* Dienstag, 16. März 2021 14:21:16 >>> *An:* squeak-dev at lists.squeakfoundation.org >>> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >>> execution for Squeak >>> >>> >>> On 16/03/21 4:51 pm, Thiede, Christoph wrote: >>> > Hi all! :-) >>> > >>> > >>> > I'm very excited to finally share my new project with you today, which >>> I >>> > call *SimulationStudio* and have made available on GitHub under [1]. >>> Its >>> > primary function is to provide an inheritable >>> > *SimulationContext* subclass of Context that makes it easy to simulate >>> > entire call trees while customizing the execution or installing custom >>> > hooks for various tracing and measurement purposes. Another >>> > accomplishment is the *Sandbox* which allows you to run arbitrary >>> > Smalltalk code in an isolated environment, separating any side effects >>> > that occur during the simulation from the rest of the image. >>> >>> This is an amazing development! >>> >>> I am not sure if you have read Warth's research at VPRI: >>> >>> World: Controlling the Scope of Side Effects by A Warth et. all, >>> >>> >>> >>> https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects >>> >>> Worlds is like your Sandbox. It also had a commit method to propagate >>> state changes from the child to the parent. This is useful when a method >>> modifies multiple state variables subject to strong invariants. A method >>> may open a World, make changes and then verify invariants are preserved >>> before committing the changes and closing the World. >>> >>> > *Limitations and challenges* >>> > >>> > Well, first of all ... *performance.* :-) Some recent measurements >>> that >>> > I have run have shown that the simulator reaches about 0.1 percent >>> (sic) >>> > of the speed of the VM executor, depending on the domain and the >>> > distribution of bytecode operations. >>> >>> I expect efficiency to improve if VM (e.g. object memory) exposes >>> primitives for object spaces with copy-on-write and white-outs (for >>> objects finalized in child space but not in parent). A sandbox could >>> carve out an object space to hold modified/deleted objects and then >>> either commit to parent or dispose it off on close. ObjectMemory already >>> has support for multiple spaces (e.g. old and young). It needs to be >>> exposed, with lots of care, to ST-side code. >>> >>> > Another challenge is the *handling of primitive operations* during the >>> > sandbox execution. >>> >>> Handling primitives, particularly those that involve physical i/o, is a >>> difficult problem. This is typically solved by using virtualization and >>> double buffering (e.g. display or input). It is ok to work with >>> non-volatile state variables for the first cut and then introduce >>> virtualization for transactional access. >>> >>> Regards .. Subbu >>> >>> >>> > > -- > -- Yoshiki > > > -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Tue Mar 16 23:38:46 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Tue, 16 Mar 2021 23:38:46 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de>, Message-ID: <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> My image hangs when loading Greases ... Can you recommend an older version of Squeak which is officially supported? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 00:20:53 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory. The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph > wrote: Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi! We still maintain the packages from VPRI. Looking at the directory, we have quite a few versions of Worlds. So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg > wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph > wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ... Looks really interesting and useful! Vanessa Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von K K Subbu > Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From Yoshiki.Ohshima at acm.org Wed Mar 17 00:02:26 2021 From: Yoshiki.Ohshima at acm.org (Yoshiki Ohshima) Date: Tue, 16 Mar 2021 17:02:26 -0700 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> Message-ID: It was created on Squeak4.2, Squeak4.4, etc. I think this one has stuff preloaded: tinlizzie.org/~ohshima/Frank-170908.zip And you need to find a VM something along the line of: 'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog 4.0.0' Let me (us) know if you have more questions! On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > My image hangs when loading Greases ... Can you recommend an older version > of Squeak which is officially supported? :-) > > > Best, > > Christoph > > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Yoshiki Ohshima > *Gesendet:* Mittwoch, 17. März 2021 00:20:53 > *An:* The general-purpose Squeak developers list > *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > W2Compiler, right? It took sometime to dig it up but it is in the Grease > package in the directory. The main things is to compile AssingmentNode > into a message call, and to avoid conflict such accessors were prefiexed > with "wiv666" ("world instance variable 666") The majority of job is done > by the W2Parser. > > On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > >> Thanks! Unfortunately, it's referring to a WCompiler which apparently is >> not part of the mcz file ... >> >> >> Best, >> >> Christoph >> >> ------------------------------ >> *Von:* Squeak-dev im >> Auftrag von Yoshiki Ohshima >> *Gesendet:* Dienstag, 16. März 2021 23:48:52 >> *An:* Vanessa Freudenberg >> *Cc:* The general-purpose Squeak developers list >> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >> execution for Squeak >> >> Hi! >> >> We still maintain the packages from VPRI. Looking at the directory, we >> have quite a few versions of Worlds. So there is a chance that it does >> something. >> >> http://tinlizzie.org/updates/exploratory/packages/ >> >> On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg >> wrote: >> >>> On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph < >>> Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: >>> >>>> One more question: Do you know where I can find the Smalltalk >>>> implementation of worlds? Is there any at all? The abstract in ResearchGate >>>> mentions this but is not addressed in the paper ... >>>> >>> Well luckily one of the authors is still on this list ... >>> >>> Looks really interesting and useful! >>> >>> Vanessa >>> >>>> Best, >>>> >>>> Christoph >>>> >>>> ------------------------------ >>>> *Von:* Thiede, Christoph >>>> *Gesendet:* Dienstag, 16. März 2021 15:10:37 >>>> *An:* squeak-dev at lists.squeakfoundation.org >>>> *Betreff:* AW: [squeak-dev] [ANN] SimulationStudio and sandboxed >>>> execution for Squeak >>>> >>>> >>>> Hi Subbu, thanks a lot for your thoughts! :-) >>>> >>>> >>>> > I am not sure if you have read Warth's research at VPRI >>>> >>>> >>>> No, I have not. Looks very interesting, I will read this! >>>> >>>> The only literature I had found on this (I have to admit that I did not >>>> spend much time on research) was this one: >>>> https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a >>>> number of problems but does not come up with a simulation solution, so it >>>> would exclusively lock your image, I guess. >>>> >>>> > I expect efficiency to improve if VM (e.g. object memory) exposes primitives >>>> for object spaces with copy-on-write and white-outs (for objects >>>> finalized in child space but not in parent). A sandbox could carve out >>>> an object space to hold modified/deleted objects and then either >>>> commit to parent or dispose it off on close. ObjectMemory already has >>>> support for multiple spaces (e.g. old and young). It needs to be exposed, >>>> with lots of care, to ST-side code. >>>> >>>> Yeah, integrating the sandbox partially into the VM would make things >>>> faster, of course ... I haven't made any attempts in this direction for two >>>> reasons: First because I, honestly, still did not find the time for getting >>>> started with VMMaker, and second because while I know that the VM is >>>> written in a Smalltalk dialect as well, it hurts me a bit that it lacks the >>>> liveness of manipulating everything from within the running image. By the >>>> way, is there already some research about unioning these two worlds in >>>> order to reprogram the VM from within the image that is running in it? I >>>> would love this. >>>> >>>> What are white-outs? I could not find any reference on this. >>>> >>>> > Handling primitives, particularly those that involve physical i/o, >>>> is a difficult problem. This is typically solved by using >>>> virtualization and double buffering (e.g. display or input). It is ok >>>> to work with non-volatile state variables for the first cut and then >>>> introduce virtualization for transactional access. >>>> >>>> Actually, my current Sandbox approach does not even intend to "commit" >>>> changes back to the rest of the image (rather to work like a Docker >>>> container in small). Thus my goal would rather be to virtualize all >>>> physical operations but keeping the effects back from the real physical >>>> devices. For filesystem accesses, for example, I thought about redirecting >>>> all write operations to a copy of the files in a special folder ... Not >>>> sure how far this approach would work well, though. >>>> >>>> For some I/O primitives, however, virtualization is rather easy. For >>>> example, when writing on the global Display, you can simply copy this >>>> object like any other object into your sandbox space/world. However, other >>>> primitives, such as from the FilePlugin, operate on state is managed >>>> outside of the image ... >>>> >>>> Best, >>>> Christoph >>>> >>>> ------------------------------ >>>> *Von:* Squeak-dev im >>>> Auftrag von K K Subbu >>>> *Gesendet:* Dienstag, 16. März 2021 14:21:16 >>>> *An:* squeak-dev at lists.squeakfoundation.org >>>> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >>>> execution for Squeak >>>> >>>> >>>> On 16/03/21 4:51 pm, Thiede, Christoph wrote: >>>> > Hi all! :-) >>>> > >>>> > >>>> > I'm very excited to finally share my new project with you today, >>>> which I >>>> > call *SimulationStudio* and have made available on GitHub under [1]. >>>> Its >>>> > primary function is to provide an inheritable >>>> > *SimulationContext* subclass of Context that makes it easy to >>>> simulate >>>> > entire call trees while customizing the execution or installing >>>> custom >>>> > hooks for various tracing and measurement purposes. Another >>>> > accomplishment is the *Sandbox* which allows you to run arbitrary >>>> > Smalltalk code in an isolated environment, separating any side >>>> effects >>>> > that occur during the simulation from the rest of the image. >>>> >>>> This is an amazing development! >>>> >>>> I am not sure if you have read Warth's research at VPRI: >>>> >>>> World: Controlling the Scope of Side Effects by A Warth et. all, >>>> >>>> >>>> >>>> https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects >>>> >>>> Worlds is like your Sandbox. It also had a commit method to propagate >>>> state changes from the child to the parent. This is useful when a >>>> method >>>> modifies multiple state variables subject to strong invariants. A >>>> method >>>> may open a World, make changes and then verify invariants are preserved >>>> before committing the changes and closing the World. >>>> >>>> > *Limitations and challenges* >>>> > >>>> > Well, first of all ... *performance.* :-) Some recent measurements >>>> that >>>> > I have run have shown that the simulator reaches about 0.1 percent >>>> (sic) >>>> > of the speed of the VM executor, depending on the domain and the >>>> > distribution of bytecode operations. >>>> >>>> I expect efficiency to improve if VM (e.g. object memory) exposes >>>> primitives for object spaces with copy-on-write and white-outs (for >>>> objects finalized in child space but not in parent). A sandbox could >>>> carve out an object space to hold modified/deleted objects and then >>>> either commit to parent or dispose it off on close. ObjectMemory >>>> already >>>> has support for multiple spaces (e.g. old and young). It needs to be >>>> exposed, with lots of care, to ST-side code. >>>> >>>> > Another challenge is the *handling of primitive operations* during >>>> the >>>> > sandbox execution. >>>> >>>> Handling primitives, particularly those that involve physical i/o, is a >>>> difficult problem. This is typically solved by using virtualization and >>>> double buffering (e.g. display or input). It is ok to work with >>>> non-volatile state variables for the first cut and then introduce >>>> virtualization for transactional access. >>>> >>>> Regards .. Subbu >>>> >>>> >>>> >> >> -- >> -- Yoshiki >> >> >> > > -- > -- Yoshiki > > > -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 17 00:35:57 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 17 Mar 2021 00:35:57 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de>, Message-ID: Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. ________________________________ Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 01:02:26 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak It was created on Squeak4.2, Squeak4.4, etc. I think this one has stuff preloaded: tinlizzie.org/~ohshima/Frank-170908.zip And you need to find a VM something along the line of: 'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog 4.0.0' Let me (us) know if you have more questions! On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph > wrote: My image hangs when loading Greases ... Can you recommend an older version of Squeak which is officially supported? :-) Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Mittwoch, 17. März 2021 00:20:53 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory. The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph > wrote: Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi! We still maintain the packages from VPRI. Looking at the directory, we have quite a few versions of Worlds. So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg > wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph > wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ... Looks really interesting and useful! Vanessa Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von K K Subbu > Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -- -- Yoshiki -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: From kksubbu.ml at gmail.com Wed Mar 17 08:01:23 2021 From: kksubbu.ml at gmail.com (K K Subbu) Date: Wed, 17 Mar 2021 13:31:23 +0530 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: Message-ID: <3911b25e-a479-386d-b4c5-6af68cc7e4c1@gmail.com> On 16/03/21 7:40 pm, Thiede, Christoph wrote: > image. By the way, is there already some research about unioning these > two worlds in order to reprogram the VM from within the image that is > running in it? I would love this. Not to my knowledge. The closest is Eliot's Cog VM simulator. ObjectMemory requires lot of work to simulate variations in bitsize, byteorder, endianness etc. > What are white-outs? I could not find any reference on this. It is a term used in systems that do fork->edit->merge-commit. It marks deleted objects like the way dirty bit marks modified ones. copy-on-write (dirty) propagates down the fork chain while white-outs propagate up the chain during merge-commit. For instance, when a directory is cached in RAM and one of its entry is deleted, the entry is marked as white-out until the cache is synced. When an object copied over (loaned) from parent sandbox becomes garbage in the child sandbox it must not be finalized or we won't be able to commit deletes to the parent. It is marked 'white-out' so that it is no longer accessible in the child. When the changes are committed to the parent, the white-out is propagated into the parent for possible finalization. If the object is strictly local to child white-outs may be dropped and the object is subject to the usual GC. > For some I/O primitives, however, virtualization is rather easy. For > example, when writing on the global Display, you can simply copy this > object like any other object into your sandbox space/world. However, > other primitives, such as from the FilePlugin, operate on state is > managed outside of the image ... This is a reasonable limitation of sandbox but is not a show-stopper for merge-commit feature. Now that memory is so affordable, speculative simulation can be a valuable feature even with this limitation. Regards .. Subbu From marcel.taeumel at hpi.de Wed Mar 17 08:13:04 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 17 Mar 2021 09:13:04 +0100 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> <,> Message-ID: Hi Christoph. > Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. Frank-170908 is based on Squeak 4.4 alpha. The VM from the Squeak 4.4 release works fine under Windows 10: http://files.squeak.org/4.4/ [http://files.squeak.org/4.4/] Best, Marcel Am 17.03.2021 01:36:08 schrieb Thiede, Christoph : Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 01:02:26 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   It was created on Squeak4.2, Squeak4.4, etc.  I think this one has stuff preloaded: tinlizzie.org/~ohshima/Frank-170908.zip [http://tinlizzie.org/~ohshima/Frank-170908.zip] And you need to find a VM something along the line of:  'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog 4.0.0' Let me (us) know if you have more questions! On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph wrote: My image hangs when loading Greases ... Can you recommend an older version of Squeak which is officially supported? :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 00:20:53 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory.  The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph wrote: Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   Hi! We still maintain the packages from VPRI.  Looking at the directory, we have quite a few versions of Worlds.  So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ [http://tinlizzie.org/updates/exploratory/packages/] On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ...    Looks really interesting and useful! Vanessa Best, Christoph [http://www.hpi.de/] Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org [mailto:squeak-dev at lists.squeakfoundation.org] Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf [https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf] It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph Von: Squeak-dev im Auftrag von K K Subbu Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org [mailto:squeak-dev at lists.squeakfoundation.org] Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all,   https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects [https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects] Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -- -- Yoshiki -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.jpg Type: image/jpeg Size: 158298 bytes Desc: not available URL: From marcel.taeumel at hpi.de Wed Mar 17 08:17:47 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 17 Mar 2021 09:17:47 +0100 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <9d1c5c70-e748-8aad-ce13-af072cd322bc@zogotounga.net> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> <7f9091b8-cedb-b4f1-a7b9-e32d1729b55e@zogotounga.net> <5b3bf865fd1649718c7cbcf40916b45f@student.hpi.uni-potsdam.de> <9d1c5c70-e748-8aad-ce13-af072cd322bc@zogotounga.net> Message-ID: Hi Stef. This is great! :-) Thanks for sharing. It's kind of groovy. I like it. Best, Marcel Am 17.03.2021 00:20:52 schrieb Stéphane Rollandin : > Nice song, I did not know the genre, but I like it. :-) I don't know the genre either :) Stef -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Wed Mar 17 08:42:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 08:42:33 0000 Subject: [squeak-dev] The Trunk: EToys-mt.434.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.434.mcz ==================== Summary ==================== Name: EToys-mt.434 Author: mt Time: 17 March 2021, 9:42:26.74561 am UUID: ea5e558c-a97f-5248-934a-3e61edede972 Ancestors: EToys-mt.433 Moves KOI8-R text converter to "Multilingual" package to avoid EToys dependency in tests. =============== Diff against EToys-mt.433 =============== Item was removed: - TextConverter subclass: #KOI8RTextConverter - instanceVariableNames: '' - classVariableNames: 'FromTable' - poolDictionaries: '' - category: 'Etoys-Squeakland-Multilingual-TextConversion'! Item was removed: - ----- Method: KOI8RTextConverter class>>encodingNames (in category 'as yet unclassified') ----- - encodingNames - - ^ #('koi8-r') copy - ! Item was removed: - ----- Method: KOI8RTextConverter class>>initialize (in category 'as yet unclassified') ----- - initialize - " - KOI8RTextConverter initialize - " - FromTable := Dictionary new. - FromTable at: 16r2500 put: 16r80. - FromTable at: 16r2502 put: 16r81. - FromTable at: 16r250C put: 16r82. - FromTable at: 16r2510 put: 16r83. - FromTable at: 16r2514 put: 16r84. - FromTable at: 16r2518 put: 16r85. - FromTable at: 16r251C put: 16r86. - FromTable at: 16r2524 put: 16r87. - FromTable at: 16r252C put: 16r88. - FromTable at: 16r2534 put: 16r89. - FromTable at: 16r253C put: 16r8A. - FromTable at: 16r2580 put: 16r8B. - FromTable at: 16r2584 put: 16r8C. - FromTable at: 16r2588 put: 16r8D. - FromTable at: 16r258C put: 16r8E. - FromTable at: 16r2590 put: 16r8F. - FromTable at: 16r2591 put: 16r90. - FromTable at: 16r2592 put: 16r91. - FromTable at: 16r2593 put: 16r92. - FromTable at: 16r2320 put: 16r93. - FromTable at: 16r25A0 put: 16r94. - FromTable at: 16r2219 put: 16r95. - FromTable at: 16r221A put: 16r96. - FromTable at: 16r2248 put: 16r97. - FromTable at: 16r2264 put: 16r98. - FromTable at: 16r2265 put: 16r99. - FromTable at: 16r00A0 put: 16r9A. - FromTable at: 16r2321 put: 16r9B. - FromTable at: 16r00B0 put: 16r9C. - FromTable at: 16r00B2 put: 16r9D. - FromTable at: 16r00B7 put: 16r9E. - FromTable at: 16r00F7 put: 16r9F. - FromTable at: 16r2550 put: 16rA0. - FromTable at: 16r2551 put: 16rA1. - FromTable at: 16r2552 put: 16rA2. - FromTable at: 16r0451 put: 16rA3. - FromTable at: 16r2553 put: 16rA4. - FromTable at: 16r2554 put: 16rA5. - FromTable at: 16r2555 put: 16rA6. - FromTable at: 16r2556 put: 16rA7. - FromTable at: 16r2557 put: 16rA8. - FromTable at: 16r2558 put: 16rA9. - FromTable at: 16r2559 put: 16rAA. - FromTable at: 16r255A put: 16rAB. - FromTable at: 16r255B put: 16rAC. - FromTable at: 16r255C put: 16rAD. - FromTable at: 16r255D put: 16rAE. - FromTable at: 16r255E put: 16rAF. - FromTable at: 16r255F put: 16rB0. - FromTable at: 16r2560 put: 16rB1. - FromTable at: 16r2561 put: 16rB2. - FromTable at: 16r0401 put: 16rB3. - FromTable at: 16r2562 put: 16rB4. - FromTable at: 16r2563 put: 16rB5. - FromTable at: 16r2564 put: 16rB6. - FromTable at: 16r2565 put: 16rB7. - FromTable at: 16r2566 put: 16rB8. - FromTable at: 16r2567 put: 16rB9. - FromTable at: 16r2568 put: 16rBA. - FromTable at: 16r2569 put: 16rBB. - FromTable at: 16r256A put: 16rBC. - FromTable at: 16r256B put: 16rBD. - FromTable at: 16r256C put: 16rBE. - FromTable at: 16r00A9 put: 16rBF. - FromTable at: 16r044E put: 16rC0. - FromTable at: 16r0430 put: 16rC1. - FromTable at: 16r0431 put: 16rC2. - FromTable at: 16r0446 put: 16rC3. - FromTable at: 16r0434 put: 16rC4. - FromTable at: 16r0435 put: 16rC5. - FromTable at: 16r0444 put: 16rC6. - FromTable at: 16r0433 put: 16rC7. - FromTable at: 16r0445 put: 16rC8. - FromTable at: 16r0438 put: 16rC9. - FromTable at: 16r0439 put: 16rCA. - FromTable at: 16r043A put: 16rCB. - FromTable at: 16r043B put: 16rCC. - FromTable at: 16r043C put: 16rCD. - FromTable at: 16r043D put: 16rCE. - FromTable at: 16r043E put: 16rCF. - FromTable at: 16r043F put: 16rD0. - FromTable at: 16r044F put: 16rD1. - FromTable at: 16r0440 put: 16rD2. - FromTable at: 16r0441 put: 16rD3. - FromTable at: 16r0442 put: 16rD4. - FromTable at: 16r0443 put: 16rD5. - FromTable at: 16r0436 put: 16rD6. - FromTable at: 16r0432 put: 16rD7. - FromTable at: 16r044C put: 16rD8. - FromTable at: 16r044B put: 16rD9. - FromTable at: 16r0437 put: 16rDA. - FromTable at: 16r0448 put: 16rDB. - FromTable at: 16r044D put: 16rDC. - FromTable at: 16r0449 put: 16rDD. - FromTable at: 16r0447 put: 16rDE. - FromTable at: 16r044A put: 16rDF. - FromTable at: 16r042E put: 16rE0. - FromTable at: 16r0410 put: 16rE1. - FromTable at: 16r0411 put: 16rE2. - FromTable at: 16r0426 put: 16rE3. - FromTable at: 16r0414 put: 16rE4. - FromTable at: 16r0415 put: 16rE5. - FromTable at: 16r0424 put: 16rE6. - FromTable at: 16r0413 put: 16rE7. - FromTable at: 16r0425 put: 16rE8. - FromTable at: 16r0418 put: 16rE9. - FromTable at: 16r0419 put: 16rEA. - FromTable at: 16r041A put: 16rEB. - FromTable at: 16r041B put: 16rEC. - FromTable at: 16r041C put: 16rED. - FromTable at: 16r041D put: 16rEE. - FromTable at: 16r041E put: 16rEF. - FromTable at: 16r041F put: 16rF0. - FromTable at: 16r042F put: 16rF1. - FromTable at: 16r0420 put: 16rF2. - FromTable at: 16r0421 put: 16rF3. - FromTable at: 16r0422 put: 16rF4. - FromTable at: 16r0423 put: 16rF5. - FromTable at: 16r0416 put: 16rF6. - FromTable at: 16r0412 put: 16rF7. - FromTable at: 16r042C put: 16rF8. - FromTable at: 16r042B put: 16rF9. - FromTable at: 16r0417 put: 16rFA. - FromTable at: 16r0428 put: 16rFB. - FromTable at: 16r042D put: 16rFC. - FromTable at: 16r0429 put: 16rFD. - FromTable at: 16r0427 put: 16rFE. - FromTable at: 16r042A put: 16rFF. - ! Item was removed: - ----- Method: KOI8RTextConverter>>fromSqueak: (in category 'as yet unclassified') ----- - fromSqueak: char - - ^ Character value: (FromTable at: char charCode ifAbsent: [char asciiValue])! Item was removed: - ----- Method: KOI8RTextConverter>>nextFromStream: (in category 'as yet unclassified') ----- - nextFromStream: aStream - - | character1 | - aStream isBinary ifTrue: [^ aStream basicNext]. - character1 := aStream basicNext. - character1 isNil ifTrue: [^ nil]. - ^ self toSqueak: character1. - ! Item was removed: - ----- Method: KOI8RTextConverter>>nextPut:toStream: (in category 'as yet unclassified') ----- - nextPut: aCharacter toStream: aStream - - | charCode | - aStream isBinary ifTrue: [ ^aCharacter storeBinaryOn: aStream ]. - (charCode := aCharacter charCode) < 256 - ifFalse: [ aStream basicNextPut: ((Character value: (self fromSqueak: aCharacter) charCode)) ] - ifTrue: [ - (latin1Encodings at: charCode + 1) - ifNil: [ aStream basicNextPut: aCharacter ] - ifNotNil: [ :encodedString | aStream basicNextPutAll: encodedString ] ]. - ^aCharacter - ! Item was removed: - ----- Method: KOI8RTextConverter>>toSqueak: (in category 'as yet unclassified') ----- - toSqueak: char - - | value | - value := char charCode. - - value < 128 ifTrue: [^ char]. - value > 255 ifTrue: [^ char]. - ^ Character leadingChar: RussianEnvironment leadingChar code: (#( - 16r2500 16r2502 16r250C 16r2510 16r2514 16r2518 16r251C 16r2524 - 16r252C 16r2534 16r253C 16r2580 16r2584 16r2588 16r258C 16r2590 - 16r2591 16r2592 16r2593 16r2320 16r25A0 16r2219 16r221A 16r2248 - 16r2264 16r2265 16r00A0 16r2321 16r00B0 16r00B2 16r00B7 16r00F7 - 16r2550 16r2551 16r2552 16r0451 16r2553 16r2554 16r2555 16r2556 - 16r2557 16r2558 16r2559 16r255A 16r255B 16r255C 16r255D 16r255E - 16r255F 16r2560 16r2561 16r0401 16r2562 16r2563 16r2564 16r2565 - 16r2566 16r2567 16r2568 16r2569 16r256A 16r256B 16r256C 16r00A9 - 16r044E 16r0430 16r0431 16r0446 16r0434 16r0435 16r0444 16r0433 - 16r0445 16r0438 16r0439 16r043A 16r043B 16r043C 16r043D 16r043E - 16r043F 16r044F 16r0440 16r0441 16r0442 16r0443 16r0436 16r0432 - 16r044C 16r044B 16r0437 16r0448 16r044D 16r0449 16r0447 16r044A - 16r042E 16r0410 16r0411 16r0426 16r0414 16r0415 16r0424 16r0413 - 16r0425 16r0418 16r0419 16r041A 16r041B 16r041C 16r041D 16r041E - 16r041F 16r042F 16r0420 16r0421 16r0422 16r0423 16r0416 16r0412 - 16r042C 16r042B 16r0417 16r0428 16r042D 16r0429 16r0427 16r042A - ) at: (value - 128 + 1)). - ! From commits at source.squeak.org Wed Mar 17 08:43:08 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 08:43:08 0000 Subject: [squeak-dev] The Trunk: Multilingual-mt.256.mcz Message-ID: Marcel Taeumel uploaded a new version of Multilingual to project The Trunk: http://source.squeak.org/trunk/Multilingual-mt.256.mcz ==================== Summary ==================== Name: Multilingual-mt.256 Author: mt Time: 17 March 2021, 9:43:06.41861 am UUID: 6f033acc-a184-ed43-9a20-375a849bcfc0 Ancestors: Multilingual-eem.255 Complements EToys-mt.434 =============== Diff against Multilingual-eem.255 =============== Item was added: + TextConverter subclass: #KOI8RTextConverter + instanceVariableNames: '' + classVariableNames: 'FromTable' + poolDictionaries: '' + category: 'Multilingual-TextConversion'! Item was added: + ----- Method: KOI8RTextConverter class>>encodingNames (in category 'as yet unclassified') ----- + encodingNames + + ^ #('koi8-r') copy + ! Item was added: + ----- Method: KOI8RTextConverter class>>initialize (in category 'as yet unclassified') ----- + initialize + " + KOI8RTextConverter initialize + " + FromTable := Dictionary new. + FromTable at: 16r2500 put: 16r80. + FromTable at: 16r2502 put: 16r81. + FromTable at: 16r250C put: 16r82. + FromTable at: 16r2510 put: 16r83. + FromTable at: 16r2514 put: 16r84. + FromTable at: 16r2518 put: 16r85. + FromTable at: 16r251C put: 16r86. + FromTable at: 16r2524 put: 16r87. + FromTable at: 16r252C put: 16r88. + FromTable at: 16r2534 put: 16r89. + FromTable at: 16r253C put: 16r8A. + FromTable at: 16r2580 put: 16r8B. + FromTable at: 16r2584 put: 16r8C. + FromTable at: 16r2588 put: 16r8D. + FromTable at: 16r258C put: 16r8E. + FromTable at: 16r2590 put: 16r8F. + FromTable at: 16r2591 put: 16r90. + FromTable at: 16r2592 put: 16r91. + FromTable at: 16r2593 put: 16r92. + FromTable at: 16r2320 put: 16r93. + FromTable at: 16r25A0 put: 16r94. + FromTable at: 16r2219 put: 16r95. + FromTable at: 16r221A put: 16r96. + FromTable at: 16r2248 put: 16r97. + FromTable at: 16r2264 put: 16r98. + FromTable at: 16r2265 put: 16r99. + FromTable at: 16r00A0 put: 16r9A. + FromTable at: 16r2321 put: 16r9B. + FromTable at: 16r00B0 put: 16r9C. + FromTable at: 16r00B2 put: 16r9D. + FromTable at: 16r00B7 put: 16r9E. + FromTable at: 16r00F7 put: 16r9F. + FromTable at: 16r2550 put: 16rA0. + FromTable at: 16r2551 put: 16rA1. + FromTable at: 16r2552 put: 16rA2. + FromTable at: 16r0451 put: 16rA3. + FromTable at: 16r2553 put: 16rA4. + FromTable at: 16r2554 put: 16rA5. + FromTable at: 16r2555 put: 16rA6. + FromTable at: 16r2556 put: 16rA7. + FromTable at: 16r2557 put: 16rA8. + FromTable at: 16r2558 put: 16rA9. + FromTable at: 16r2559 put: 16rAA. + FromTable at: 16r255A put: 16rAB. + FromTable at: 16r255B put: 16rAC. + FromTable at: 16r255C put: 16rAD. + FromTable at: 16r255D put: 16rAE. + FromTable at: 16r255E put: 16rAF. + FromTable at: 16r255F put: 16rB0. + FromTable at: 16r2560 put: 16rB1. + FromTable at: 16r2561 put: 16rB2. + FromTable at: 16r0401 put: 16rB3. + FromTable at: 16r2562 put: 16rB4. + FromTable at: 16r2563 put: 16rB5. + FromTable at: 16r2564 put: 16rB6. + FromTable at: 16r2565 put: 16rB7. + FromTable at: 16r2566 put: 16rB8. + FromTable at: 16r2567 put: 16rB9. + FromTable at: 16r2568 put: 16rBA. + FromTable at: 16r2569 put: 16rBB. + FromTable at: 16r256A put: 16rBC. + FromTable at: 16r256B put: 16rBD. + FromTable at: 16r256C put: 16rBE. + FromTable at: 16r00A9 put: 16rBF. + FromTable at: 16r044E put: 16rC0. + FromTable at: 16r0430 put: 16rC1. + FromTable at: 16r0431 put: 16rC2. + FromTable at: 16r0446 put: 16rC3. + FromTable at: 16r0434 put: 16rC4. + FromTable at: 16r0435 put: 16rC5. + FromTable at: 16r0444 put: 16rC6. + FromTable at: 16r0433 put: 16rC7. + FromTable at: 16r0445 put: 16rC8. + FromTable at: 16r0438 put: 16rC9. + FromTable at: 16r0439 put: 16rCA. + FromTable at: 16r043A put: 16rCB. + FromTable at: 16r043B put: 16rCC. + FromTable at: 16r043C put: 16rCD. + FromTable at: 16r043D put: 16rCE. + FromTable at: 16r043E put: 16rCF. + FromTable at: 16r043F put: 16rD0. + FromTable at: 16r044F put: 16rD1. + FromTable at: 16r0440 put: 16rD2. + FromTable at: 16r0441 put: 16rD3. + FromTable at: 16r0442 put: 16rD4. + FromTable at: 16r0443 put: 16rD5. + FromTable at: 16r0436 put: 16rD6. + FromTable at: 16r0432 put: 16rD7. + FromTable at: 16r044C put: 16rD8. + FromTable at: 16r044B put: 16rD9. + FromTable at: 16r0437 put: 16rDA. + FromTable at: 16r0448 put: 16rDB. + FromTable at: 16r044D put: 16rDC. + FromTable at: 16r0449 put: 16rDD. + FromTable at: 16r0447 put: 16rDE. + FromTable at: 16r044A put: 16rDF. + FromTable at: 16r042E put: 16rE0. + FromTable at: 16r0410 put: 16rE1. + FromTable at: 16r0411 put: 16rE2. + FromTable at: 16r0426 put: 16rE3. + FromTable at: 16r0414 put: 16rE4. + FromTable at: 16r0415 put: 16rE5. + FromTable at: 16r0424 put: 16rE6. + FromTable at: 16r0413 put: 16rE7. + FromTable at: 16r0425 put: 16rE8. + FromTable at: 16r0418 put: 16rE9. + FromTable at: 16r0419 put: 16rEA. + FromTable at: 16r041A put: 16rEB. + FromTable at: 16r041B put: 16rEC. + FromTable at: 16r041C put: 16rED. + FromTable at: 16r041D put: 16rEE. + FromTable at: 16r041E put: 16rEF. + FromTable at: 16r041F put: 16rF0. + FromTable at: 16r042F put: 16rF1. + FromTable at: 16r0420 put: 16rF2. + FromTable at: 16r0421 put: 16rF3. + FromTable at: 16r0422 put: 16rF4. + FromTable at: 16r0423 put: 16rF5. + FromTable at: 16r0416 put: 16rF6. + FromTable at: 16r0412 put: 16rF7. + FromTable at: 16r042C put: 16rF8. + FromTable at: 16r042B put: 16rF9. + FromTable at: 16r0417 put: 16rFA. + FromTable at: 16r0428 put: 16rFB. + FromTable at: 16r042D put: 16rFC. + FromTable at: 16r0429 put: 16rFD. + FromTable at: 16r0427 put: 16rFE. + FromTable at: 16r042A put: 16rFF. + ! Item was added: + ----- Method: KOI8RTextConverter>>fromSqueak: (in category 'as yet unclassified') ----- + fromSqueak: char + + ^ Character value: (FromTable at: char charCode ifAbsent: [char asciiValue])! Item was added: + ----- Method: KOI8RTextConverter>>nextFromStream: (in category 'as yet unclassified') ----- + nextFromStream: aStream + + | character1 | + aStream isBinary ifTrue: [^ aStream basicNext]. + character1 := aStream basicNext. + character1 isNil ifTrue: [^ nil]. + ^ self toSqueak: character1. + ! Item was added: + ----- Method: KOI8RTextConverter>>nextPut:toStream: (in category 'as yet unclassified') ----- + nextPut: aCharacter toStream: aStream + + | charCode | + aStream isBinary ifTrue: [ ^aCharacter storeBinaryOn: aStream ]. + (charCode := aCharacter charCode) < 256 + ifFalse: [ aStream basicNextPut: ((Character value: (self fromSqueak: aCharacter) charCode)) ] + ifTrue: [ + (latin1Encodings at: charCode + 1) + ifNil: [ aStream basicNextPut: aCharacter ] + ifNotNil: [ :encodedString | aStream basicNextPutAll: encodedString ] ]. + ^aCharacter + ! Item was added: + ----- Method: KOI8RTextConverter>>toSqueak: (in category 'as yet unclassified') ----- + toSqueak: char + + | value | + value := char charCode. + + value < 128 ifTrue: [^ char]. + value > 255 ifTrue: [^ char]. + ^ Character leadingChar: RussianEnvironment leadingChar code: (#( + 16r2500 16r2502 16r250C 16r2510 16r2514 16r2518 16r251C 16r2524 + 16r252C 16r2534 16r253C 16r2580 16r2584 16r2588 16r258C 16r2590 + 16r2591 16r2592 16r2593 16r2320 16r25A0 16r2219 16r221A 16r2248 + 16r2264 16r2265 16r00A0 16r2321 16r00B0 16r00B2 16r00B7 16r00F7 + 16r2550 16r2551 16r2552 16r0451 16r2553 16r2554 16r2555 16r2556 + 16r2557 16r2558 16r2559 16r255A 16r255B 16r255C 16r255D 16r255E + 16r255F 16r2560 16r2561 16r0401 16r2562 16r2563 16r2564 16r2565 + 16r2566 16r2567 16r2568 16r2569 16r256A 16r256B 16r256C 16r00A9 + 16r044E 16r0430 16r0431 16r0446 16r0434 16r0435 16r0444 16r0433 + 16r0445 16r0438 16r0439 16r043A 16r043B 16r043C 16r043D 16r043E + 16r043F 16r044F 16r0440 16r0441 16r0442 16r0443 16r0436 16r0432 + 16r044C 16r044B 16r0437 16r0448 16r044D 16r0449 16r0447 16r044A + 16r042E 16r0410 16r0411 16r0426 16r0414 16r0415 16r0424 16r0413 + 16r0425 16r0418 16r0419 16r041A 16r041B 16r041C 16r041D 16r041E + 16r041F 16r042F 16r0420 16r0421 16r0422 16r0423 16r0416 16r0412 + 16r042C 16r042B 16r0417 16r0428 16r042D 16r0429 16r0427 16r042A + ) at: (value - 128 + 1)). + ! From commits at source.squeak.org Wed Mar 17 10:09:18 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 10:09:18 0000 Subject: [squeak-dev] The Trunk: PackageInfo-Base-mt.73.mcz Message-ID: Marcel Taeumel uploaded a new version of PackageInfo-Base to project The Trunk: http://source.squeak.org/trunk/PackageInfo-Base-mt.73.mcz ==================== Summary ==================== Name: PackageInfo-Base-mt.73 Author: mt Time: 17 March 2021, 11:09:17.917193 am UUID: 6997c545-3e89-d140-8c54-65f1ef4b15e7 Ancestors: PackageInfo-Base-mt.72 In packages, fixes inclusion test for invalid method references. Class organization cannot distinguish between 'as yet unclassified' and 'not even in the class'. =============== Diff against PackageInfo-Base-mt.72 =============== Item was changed: ----- Method: PackageInfo>>includesMethod:ofClass: (in category 'testing') ----- includesMethod: aSymbol ofClass: aClass aClass ifNil: [^ false]. + (aClass includesSelector: aSymbol) ifFalse: [^ false]. ^ self includesMethodCategory: ((aClass organization categoryOfElement: aSymbol) ifNil: [' ']) ofClass: aClass! From herbertkoenig at gmx.net Wed Mar 17 10:44:29 2021 From: herbertkoenig at gmx.net (=?UTF-8?Q?Herbert_K=c3=b6nig?=) Date: Wed, 17 Mar 2021 11:44:29 +0100 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> Message-ID: <4dec21eb-bd19-187f-907f-7cad830c3e3c@gmx.net> Hi Stef, Impressive! As an outer world person I looked through the site but didn't find any Screenshots. *I'd like to see the UI you're working in, be it a lot of workspaces.* My UI usually is inspectors / explorers on Objects with messages I send to them. Sometimes just some buttons placed in the World. Making a GUI often is more than doubling the effort. Cheers, Herbert Am 16.03.2021 um 18:40 schrieb Stéphane Rollandin: > Hello all, > > I just finished a new piece of music entirely composed and performed > within a muO image - the audio is recorded from virtual instruments > fed a live MIDI output stream. This is done with a technology that > does not exists elsewhere. > > I know it is not the place to post (weird) music, but in the broader > context of the discussion about the death of Smalltalk, I felt > inclined to illustrate how for some of us it is very much alive and > singing. > > Here it is: > > http://www.zogotounga.net/zik/Pentaxoyothol.ogg > > Stef > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 17 12:31:50 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 17 Mar 2021 12:31:50 +0000 Subject: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) Message-ID: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> Hi all! After announcing SimulationStudio and Sandbox yesterday [3], today I'm happy to introduce you to two other repositories which I have been working at during the last months. Last week, I had the pleasure to present them during the German Squeak Winter Demos [4]. Drum roll, say hello to TelegramBot [1] & TelegramSmalltalkBot [2]! :-) TelegramBot is a small framework I built to make it possible to implement bots for the Telegram messenger [5]. It uses the official Telegram Bot REST API [6] and maps it to an object-oriented design in Squeak, providing support for different bot capabilities such as message sending, receiving, and editing. It also allows sending multi-media message types such as pictures (Forms), formatted messages (Texts), audio messages (AbstractSounds), and some others. Last but not least, it comprises a small API to host your bots in a background process of the image. For more information, check out the README.md of the repository in [1]. TelegramSmalltalkBot is a second repository that implements a Telegram bot for evaluating Smalltalk expressions by using the TelegramBot framework from above. Do you know this situation when you wonder "how does XYZ work in Squeak" and cannot check it out because you do not have any PC or laptop at hand right now? This situation is history as of today, just send a message to the bot from wherever you are, just using your phone or even your watch! In a nutshell, TelegramSmalltalkBot is a simple REPL shell that utilizes the Squeak Compiler, but it's also packed with a number of convenient features that make remote access to your image much more pleasant. For example, the bot does not only answer plain text but also multi-media messages such as pictures or files depending on the results of your expressions. You can also use Workspace-like variable bindings or reply to older messages from the bot to bind the receiver of your message. For an exhaustive list of all features, visit the repository in [2] or just send /help to the bot. I also have uploaded a short video demo about it at [7]. Another important thing to note is that TelegramSmalltalkBot is able to evaluate every expression in a sandboxed execution environment by using the SimulationStudio library I announced yesterday [3]. While both projects have grown rather independently of each other, this usage fills an important gap for me and I think it is a relevant real-world use case of the Sandbox. Please try it out! :-) All you need is a Telegram account for free and a client (Telegram is available cross-platform and can also be used from the web). I am hosting an instance of the bot myself on my raspberry pi and I feel confident enough about the isolation quality of my Sandbox that I dare to unlock public access to the bot for everyone. A small architecture diagram which I have shown at the Winter Demos is in the attachments (contains clickable links to the repositories), you can also find it in the wiki of [2]. Just search in the Telegram app for @SqueakSmalltalkBot or follow this link: https://t.me/SqueakSmalltalkBot [8] (QR code is also in the attachments) I'm very much looking forward to your feedback! If you experience any problems or have new ideas, please let me know via squeak-dev or GitHub issues! I'm already planning many new features for the bot - be sure to watch the repository if you are interested in them. :-) Best, Christoph [1] https://github.com/LinqLover/TelegramBot [2] https://github.com/LinqLover/TelegramSmalltalkBot [3] http://forum.world.st/ANN-SimulationStudio-and-sandboxed-execution-for-Squeak-td5127804.html [4] http://forum.world.st/Squeak-Winter-Demos-2021-03-06-3-p-m-6-p-m-CET-virtual-tp5126913.html [5] https://telegram.org [6] https://core.telegram.org/bots/api [7] https://youtu.be/HZCeThLqQmg [8] https://t.me/SqueakSmalltalkBot -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: TelegramSmalltalkBot Architecture.svg Type: image/svg+xml Size: 551107 bytes Desc: TelegramSmalltalkBot Architecture.svg URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: qr_ at SqueakSmalltalkBot.png Type: image/png Size: 5817 bytes Desc: qr_ at SqueakSmalltalkBot.png URL: From lproven at gmail.com Wed Mar 17 12:59:17 2021 From: lproven at gmail.com (Liam Proven) Date: Wed, 17 Mar 2021 13:59:17 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: On Tue, 16 Mar 2021 at 20:09, tim Rowledge wrote: > > Liam, our problem here is at least in part one of weariness. If you were to read back in the mail list archives you'd find ... many, perhaps hundreds?... of times when somebody has asked us collectively to explain "why Smalltalk?" Sometimes it is genuinely curious people that want to understand, that listen and then join the collective, err, I mean the team. > > Often, so very often, it is somebody wanting a fight over some crypto-religious point. Bizarrely, quite a lot of people seem to be threatened by the idea of a not-dead-text-in-files world. A looong time ago we suffered a prolonged attack of "it must be changed to be just like Visual BASIC or it will die!!!" demands. Dan Ingalls even responded by making an alternate syntax setup that allowed code to be written and presented as a BASIC-like text. That is impressive! > We have long suffered from drive-by idiocy telling us that an interpreted language with all that wasteful trash of structure and garbage collection and message sending cannot possibly work and will always be slow and nobody will ever understand it and you can't write applications in it and real programmers use XXXXX (where XXXXX is flavour of the month on some gitidiot/slashdot type site) and by the way you people have bad breath. Presenting facts does essentially nothing to stop this. Well, I do sympathise. I have been digging into language and OS design for more than a decade now, and I keep finding impressive, inspiring new developments that get shouted down by _hoi polloi_ because they are different and not like what people are used to. > If you want to see some decent quality Smalltalk evangelism and explanation, try quora.com and look for articles by people like 'Mr Smalltalk', Richard Eng. He's had to pretty much retire from this effort for medical reasons but he put a *lot* of effort into presenting things. Obviously, never look at any other parts of Quora - the site that is an existence proof that not only are there, in fact, stupid questions but that there is a near infinite supply of people wanting to ask them again and again and again. Ha! I have been banned from Quora. My crime was using a fake name. My account name was "Liam Proven", my actual, real, legal name since birth and what it says on my passport. "Proven" is a buzzword on Quora, clearly. > The couple of tweets you pointed to seem to me to be excellent examples of people that have no interest at all in understanding or learning anything new. It's just another case of "somebody is wrong on the internet" and I fear most of us here are a bit worn out with that. ISWYM. I had hoped for some rebuttal that I could send back, but I see that that would be a big ask when everyone's tired of the same sort of heckling. :'( -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 17 13:05:52 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 17 Mar 2021 13:05:52 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> <,> , Message-ID: Hi Marcel, it's not working for me: --------------------------- Squeak! --------------------------- Could not open the Squeak image file 'C:\Users\Christoph\OneDrive\Downloads\Squeak-4.4-All-in-One\Squeak-4.4-All-in-One.app\Contents\Resources\Squeak4.4-12327.image' There are several ways to open an image file. You can: 1. Double-click on the desired image file. 2. Drop the image file onto the application. Aborting... --------------------------- OK --------------------------- How am I supposed to tell the VM which image file to load? It always wants to open the Squeak4.4-12327.image file only. Dropping another image file on the executable only gives me a load error from within the 4.4 image. The message above is a result of replacing the default image and changes file in the AllInOne bundle with frank.image and frank.changes. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 17. März 2021 09:13:04 An: squeak-dev Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Christoph. > Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. Frank-170908 is based on Squeak 4.4 alpha. The VM from the Squeak 4.4 release works fine under Windows 10: http://files.squeak.org/4.4/ [cid:11eb6d47-a68a-4fb2-bc31-a09ad62f2673] Best, Marcel Am 17.03.2021 01:36:08 schrieb Thiede, Christoph : Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. ________________________________ Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 01:02:26 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak It was created on Squeak4.2, Squeak4.4, etc. I think this one has stuff preloaded: tinlizzie.org/~ohshima/Frank-170908.zip And you need to find a VM something along the line of: 'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog 4.0.0' Let me (us) know if you have more questions! On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph > wrote: My image hangs when loading Greases ... Can you recommend an older version of Squeak which is officially supported? :-) Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Mittwoch, 17. März 2021 00:20:53 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory. The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph > wrote: Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi! We still maintain the packages from VPRI. Looking at the directory, we have quite a few versions of Worlds. So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg > wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph > wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ... Looks really interesting and useful! Vanessa Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von K K Subbu > Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -- -- Yoshiki -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.jpg Type: image/jpeg Size: 158298 bytes Desc: image.jpg URL: From marcel.taeumel at hpi.de Wed Mar 17 13:12:12 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Wed, 17 Mar 2021 14:12:12 +0100 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> <,> <,> Message-ID: Hi Christoph. > How am I supposed to tell the VM which image file to load? It always wants to open the Squeak4.4-12327.image file only. Change the .ini file :-) Remove the hard-coded path in there. > The message above is a result of replacing the default image and changes file in the AllInOne bundle with frank.image and frank.changes. I suppose you need the other DLLs and resources, too? What I tried was to copy the VM files over to the contents from the ZIP file. That worked. :-) Best, Marcel Am 17.03.2021 14:06:05 schrieb Thiede, Christoph : Hi Marcel, it's not working for me: --------------------------- Squeak! --------------------------- Could not open the Squeak image file 'C:\Users\Christoph\OneDrive\Downloads\Squeak-4.4-All-in-One\Squeak-4.4-All-in-One.app\Contents\Resources\Squeak4.4-12327.image' There are several ways to open an image file. You can:   1. Double-click on the desired image file.   2. Drop the image file onto the application. Aborting... --------------------------- OK    --------------------------- How am I supposed to tell the VM which image file to load? It always wants to open the Squeak4.4-12327.image file only. Dropping another image file on the executable only gives me a load error from within the 4.4 image. The message above is a result of replacing the default image and changes file in the AllInOne bundle with frank.image and frank.changes. Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 17. März 2021 09:13:04 An: squeak-dev Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   Hi Christoph. > Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. Frank-170908 is based on Squeak 4.4 alpha. The VM from the Squeak 4.4 release works fine under Windows 10: http://files.squeak.org/4.4/ [http://files.squeak.org/4.4/] Best, Marcel Am 17.03.2021 01:36:08 schrieb Thiede, Christoph : Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 01:02:26 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   It was created on Squeak4.2, Squeak4.4, etc.  I think this one has stuff preloaded: tinlizzie.org/~ohshima/Frank-170908.zip [http://tinlizzie.org/~ohshima/Frank-170908.zip] And you need to find a VM something along the line of:  'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog 4.0.0' Let me (us) know if you have more questions! On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph wrote: My image hangs when loading Greases ... Can you recommend an older version of Squeak which is officially supported? :-) Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 00:20:53 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory.  The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph wrote: Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph [http://www.hpi.de/] Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   Hi! We still maintain the packages from VPRI.  Looking at the directory, we have quite a few versions of Worlds.  So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ [http://tinlizzie.org/updates/exploratory/packages/] On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ...    Looks really interesting and useful! Vanessa Best, Christoph [http://www.hpi.de/] Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org [mailto:squeak-dev at lists.squeakfoundation.org] Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf [https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf] It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph Von: Squeak-dev im Auftrag von K K Subbu Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org [mailto:squeak-dev at lists.squeakfoundation.org] Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak   On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all,   https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects [https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects] Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -- -- Yoshiki -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.jpg Type: image/jpeg Size: 158298 bytes Desc: not available URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 17 13:28:58 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 17 Mar 2021 13:28:58 +0000 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> <,> <,> , Message-ID: <3d123ad21ef14d4d8c13d34701afe72c@student.hpi.uni-potsdam.de> Hi Marcel, ah, that was missing! Thank you. :-) Some first impressions of the Worlds implementation for Squeak: If I understand correctly, it only works with objects that explicitly support the worlds mechanism. So for example: z := #(1). world := WWorld thisWorld sprout. {world eval: [ z at: 1 put: 2. z]. z} "==> #(#(2) #(2)) Sandbox would answer: z := #(1). {Sandbox evaluate: [ z at: 1 put: 2. z]. z} "==> #(#(2) #(1))" For Worlds, I apparently would need to use a specialized WArray instead. This has the advantage of being much faster than Sandbox but also the disadvantage of not fitting for general-purpose Smalltalk expressions. Still, a very interesting approach! Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 17. März 2021 14:12:12 An: squeak-dev Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Christoph. > How am I supposed to tell the VM which image file to load? It always wants to open the Squeak4.4-12327.image file only. Change the .ini file :-) Remove the hard-coded path in there. > The message above is a result of replacing the default image and changes file in the AllInOne bundle with frank.image and frank.changes. I suppose you need the other DLLs and resources, too? What I tried was to copy the VM files over to the contents from the ZIP file. That worked. :-) Best, Marcel Am 17.03.2021 14:06:05 schrieb Thiede, Christoph : Hi Marcel, it's not working for me: --------------------------- Squeak! --------------------------- Could not open the Squeak image file 'C:\Users\Christoph\OneDrive\Downloads\Squeak-4.4-All-in-One\Squeak-4.4-All-in-One.app\Contents\Resources\Squeak4.4-12327.image' There are several ways to open an image file. You can: 1. Double-click on the desired image file. 2. Drop the image file onto the application. Aborting... --------------------------- OK --------------------------- How am I supposed to tell the VM which image file to load? It always wants to open the Squeak4.4-12327.image file only. Dropping another image file on the executable only gives me a load error from within the 4.4 image. The message above is a result of replacing the default image and changes file in the AllInOne bundle with frank.image and frank.changes. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Mittwoch, 17. März 2021 09:13:04 An: squeak-dev Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Christoph. > Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. Frank-170908 is based on Squeak 4.4 alpha. The VM from the Squeak 4.4 release works fine under Windows 10: http://files.squeak.org/4.4/ [cid:11eb6d47-a68a-4fb2-bc31-a09ad62f2673] Best, Marcel Am 17.03.2021 01:36:08 schrieb Thiede, Christoph : Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. ________________________________ Von: Squeak-dev im Auftrag von Yoshiki Ohshima Gesendet: Mittwoch, 17. März 2021 01:02:26 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak It was created on Squeak4.2, Squeak4.4, etc. I think this one has stuff preloaded: tinlizzie.org/~ohshima/Frank-170908.zip And you need to find a VM something along the line of: 'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog 4.0.0' Let me (us) know if you have more questions! On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph > wrote: My image hangs when loading Greases ... Can you recommend an older version of Squeak which is officially supported? :-) Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Mittwoch, 17. März 2021 00:20:53 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak W2Compiler, right? It took sometime to dig it up but it is in the Grease package in the directory. The main things is to compile AssingmentNode into a message call, and to avoid conflict such accessors were prefiexed with "wiv666" ("world instance variable 666") The majority of job is done by the W2Parser. On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph > wrote: Thanks! Unfortunately, it's referring to a WCompiler which apparently is not part of the mcz file ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Yoshiki Ohshima > Gesendet: Dienstag, 16. März 2021 23:48:52 An: Vanessa Freudenberg Cc: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi! We still maintain the packages from VPRI. Looking at the directory, we have quite a few versions of Worlds. So there is a chance that it does something. http://tinlizzie.org/updates/exploratory/packages/ On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg > wrote: On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph > wrote: One more question: Do you know where I can find the Smalltalk implementation of worlds? Is there any at all? The abstract in ResearchGate mentions this but is not addressed in the paper ... Well luckily one of the authors is still on this list ... Looks really interesting and useful! Vanessa Best, Christoph ________________________________ Von: Thiede, Christoph Gesendet: Dienstag, 16. März 2021 15:10:37 An: squeak-dev at lists.squeakfoundation.org Betreff: AW: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak Hi Subbu, thanks a lot for your thoughts! :-) > I am not sure if you have read Warth's research at VPRI No, I have not. Looks very interesting, I will read this! The only literature I had found on this (I have to admit that I did not spend much time on research) was this one: https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a number of problems but does not come up with a simulation solution, so it would exclusively lock your image, I guess. > I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. Yeah, integrating the sandbox partially into the VM would make things faster, of course ... I haven't made any attempts in this direction for two reasons: First because I, honestly, still did not find the time for getting started with VMMaker, and second because while I know that the VM is written in a Smalltalk dialect as well, it hurts me a bit that it lacks the liveness of manipulating everything from within the running image. By the way, is there already some research about unioning these two worlds in order to reprogram the VM from within the image that is running in it? I would love this. What are white-outs? I could not find any reference on this. > Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Actually, my current Sandbox approach does not even intend to "commit" changes back to the rest of the image (rather to work like a Docker container in small). Thus my goal would rather be to virtualize all physical operations but keeping the effects back from the real physical devices. For filesystem accesses, for example, I thought about redirecting all write operations to a copy of the files in a special folder ... Not sure how far this approach would work well, though. For some I/O primitives, however, virtualization is rather easy. For example, when writing on the global Display, you can simply copy this object like any other object into your sandbox space/world. However, other primitives, such as from the FilePlugin, operate on state is managed outside of the image ... Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von K K Subbu > Gesendet: Dienstag, 16. März 2021 14:21:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak On 16/03/21 4:51 pm, Thiede, Christoph wrote: > Hi all! :-) > > > I'm very excited to finally share my new project with you today, which I > call *SimulationStudio* and have made available on GitHub under [1]. Its > primary function is to provide an inheritable > *SimulationContext* subclass of Context that makes it easy to simulate > entire call trees while customizing the execution or installing custom > hooks for various tracing and measurement purposes. Another > accomplishment is the *Sandbox* which allows you to run arbitrary > Smalltalk code in an isolated environment, separating any side effects > that occur during the simulation from the rest of the image. This is an amazing development! I am not sure if you have read Warth's research at VPRI: World: Controlling the Scope of Side Effects by A Warth et. all, https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects Worlds is like your Sandbox. It also had a commit method to propagate state changes from the child to the parent. This is useful when a method modifies multiple state variables subject to strong invariants. A method may open a World, make changes and then verify invariants are preserved before committing the changes and closing the World. > *Limitations and challenges* > > Well, first of all ... *performance.* :-) Some recent measurements that > I have run have shown that the simulator reaches about 0.1 percent (sic) > of the speed of the VM executor, depending on the domain and the > distribution of bytecode operations. I expect efficiency to improve if VM (e.g. object memory) exposes primitives for object spaces with copy-on-write and white-outs (for objects finalized in child space but not in parent). A sandbox could carve out an object space to hold modified/deleted objects and then either commit to parent or dispose it off on close. ObjectMemory already has support for multiple spaces (e.g. old and young). It needs to be exposed, with lots of care, to ST-side code. > Another challenge is the *handling of primitive operations* during the > sandbox execution. Handling primitives, particularly those that involve physical i/o, is a difficult problem. This is typically solved by using virtualization and double buffering (e.g. display or input). It is ok to work with non-volatile state variables for the first cut and then introduce virtualization for transactional access. Regards .. Subbu -- -- Yoshiki -- -- Yoshiki -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.jpg Type: image/jpeg Size: 158298 bytes Desc: image.jpg URL: From commits at source.squeak.org Wed Mar 17 14:15:10 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:15:10 0000 Subject: [squeak-dev] The Trunk: EToys-mt.435.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.435.mcz ==================== Summary ==================== Name: EToys-mt.435 Author: mt Time: 17 March 2021, 3:15:04.484151 pm UUID: 4951443f-e7ab-6c45-9901-0509281a39ac Ancestors: EToys-mt.434 Further untangles Etoys from other packages: - Moves webcam stuff to MorphicExtras - Moves PointType to Protocols (i.e. vocabularies) - Clean up vocabularies when unloading Etoys =============== Diff against EToys-mt.434 =============== Item was changed: SystemOrganization addCategory: #'Etoys-Buttons'! SystemOrganization addCategory: #'Etoys-CustomEvents'! SystemOrganization addCategory: #'Etoys-Experimental'! SystemOrganization addCategory: #'Etoys-OLPC-Display'! SystemOrganization addCategory: #'Etoys-Outliner'! SystemOrganization addCategory: #'Etoys-Protocols'! SystemOrganization addCategory: #'Etoys-Protocols-Type Vocabularies'! SystemOrganization addCategory: #'Etoys-ReleaseBuilder'! SystemOrganization addCategory: #'Etoys-Scripting'! SystemOrganization addCategory: #'Etoys-Scripting Support'! SystemOrganization addCategory: #'Etoys-Scripting Tiles'! SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Base'! SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Connectors'! SystemOrganization addCategory: #'Etoys-Squeakland-EToys-Kedama'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Buttons'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Calendar'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Debugger'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Help'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Input'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Support'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Tiles'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-SpeechBubbles'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Tile Scriptors'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Text'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Intersection'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Simplification'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Triangulation'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Basic'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Books'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Components'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Demo'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Experimental'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess960'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-GeeMail'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Kernel'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Mentoring'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Navigators'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PDA'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PartsBin'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Support'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Widgets'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Windows'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Worlds'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-AdditionalMorphs'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Charts'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Postscript Filters'! - SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-WebCam'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Widgets'! SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-Languages'! SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-TextConversion'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Formatter'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Forms'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser Entities'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Tokenizer'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-MIME'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-TelNet WordNet'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-UI'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-Url'! SystemOrganization addCategory: #'Etoys-Squeakland-Protocols-Type Vocabularies'! SystemOrganization addCategory: #'Etoys-Squeakland-SISS-Serialization'! SystemOrganization addCategory: #'Etoys-Squeakland-ST80-Morphic'! SystemOrganization addCategory: #'Etoys-Squeakland-SUnit'! SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Interface'! SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Ogg'! SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Scores'! SystemOrganization addCategory: #'Etoys-Squeakland-Sugar'! SystemOrganization addCategory: #'Etoys-Squeakland-Support'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Clipboard-Extended'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Compiler'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Exceptions Kernel'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Support'! SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Changes'! SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Explorer'! SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Process Browser'! SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ObjectVectors'! SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTree-AttributeDefinition'! SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTreeTransformer'! SystemOrganization addCategory: #'Etoys-Stacks'! SystemOrganization addCategory: #'Etoys-StarSqueak'! SystemOrganization addCategory: #'Etoys-Support'! SystemOrganization addCategory: #'Etoys-Tests'! SystemOrganization addCategory: #'Etoys-Tile Scriptors'! SystemOrganization addCategory: #'Etoys-UserInterfaceTheme'! SystemOrganization addCategory: #'Etoys-Widgets'! Item was removed: - Object subclass: #CameraInterface - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-MorphicExtras-WebCam'! - - !CameraInterface commentStamp: 'eem 10/16/2020 10:53' prior: 0! - CameraInterface: Simple cross-platform webcam access interface adapted from MIT Scratch. Changes made so that different cameras can be tested when more than one is connected, and so that the interface is simpler and may be interrupt-driven. - - [| form | - form := Form extent: 352 @ 288 depth: 32. - CameraInterface - openCamera: 1 width: form width height: form height; - trySetSemaphoreForCamera: 1. - [Sensor noButtonPressed] whileTrue: - [CameraInterface - waitForNextFrame: 1 timeout: 2000; - getFrameForCamera: 1 into: form bits. - form displayAt: Sensor cursorPoint]] ensure: [CameraInterface closeCamera: 1] - - Copyright (c) 2009 Massachusetts Institute of Technology - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE.! Item was removed: - ----- Method: CameraInterface class>>camera:framesDo:while: (in category 'utilities') ----- - camera: cameraNum framesDo: aBlock while: whileBlock - "Evaluate aBlock every time a frame becomes available. Answer a tuple of frames per second and number of 16ms delays per second. - Be destructive; use only one bitmap, overwriting its contents with each successive frame. - It is the sender's responsibility to open and close the camera." - | form bitmap delay start duration frameCount delayCount | - form := Form - extent: (self frameExtent: cameraNum) - depth: 32. - bitmap := form bits. - delay := Delay forMilliseconds: (1000 / 60) asInteger. "60 fps is fast" - start := Time utcMicrosecondClock. - frameCount := delayCount := 0. - [[(self camera: cameraNum getParam: 1) <= 0] whileTrue: - [delay wait. delayCount := delayCount + 1]. - self getFrameForCamera: cameraNum into: bitmap. - frameCount := frameCount + 1. - aBlock value: form. - whileBlock value] whileTrue. - ^{ frameCount * 1.0e6 / (duration := Time utcMicrosecondClock - start). - delayCount * 1.0e6 / duration } - - "| cameraNum | - self openCamera: (cameraNum := 1) width: 640 height: 480. - self waitForCameraStart: cameraNum. - [self camera: cameraNum framesDo: [:bitmap| bitmap display] while: [Sensor noButtonPressed]] ensure: - [self closeCamera: cameraNum]"! Item was removed: - ----- Method: CameraInterface class>>camera:getParam: (in category 'camera ops') ----- - camera: cameraNum getParam: paramNum - "Answer the given parameter for the given camera. - param 1 is the frame count, the number of frames grabbed since the last send of getFrameForCamera:into: - param 2 is the size of the bitmap in bytes required for an image" - - - ^nil - ! Item was removed: - ----- Method: CameraInterface class>>camera:setSemaphore: (in category 'camera ops') ----- - camera: cameraNum setSemaphore: semaphoreIndex - "Set an external semaphore index through which to signal that a frame is available. - Fail if cameraNum does not reference an open camera, or if the platform does not - support interrupt-driven frame receipt." - - ^self primitiveFailed! Item was removed: - ----- Method: CameraInterface class>>cameraDevices (in category 'utilities') ----- - cameraDevices - "CameraInterface cameraDevices" - ^Array streamContents: - [:s| | i | - i := 1. - [(self cameraName: i) - ifNotNil: [:cameraName| s nextPut: cameraName. true] - ifNil: [false]] whileTrue: [i := i + 1]]! Item was removed: - ----- Method: CameraInterface class>>cameraGetSemaphore: (in category 'camera ops') ----- - cameraGetSemaphore: cameraNum - "Answer the external semaphore index through which to signal that a frame is available. - Fail if cameraNum has not had a semaphore index set, or is otherwise invalid. - Answer nil on failure for convenience." - - ^nil! Item was removed: - ----- Method: CameraInterface class>>cameraIsAvailable (in category 'camera ops') ----- - cameraIsAvailable - "Answer true if at least one camera is available." - - ^(self cameraName: 1) notNil - ! Item was removed: - ----- Method: CameraInterface class>>cameraIsOpen: (in category 'camera ops') ----- - cameraIsOpen: cameraNum - "Answer true if the camera is open." - - ^ (self packedFrameExtent: cameraNum) > 0 - ! Item was removed: - ----- Method: CameraInterface class>>cameraName: (in category 'camera ops') ----- - cameraName: cameraNum - "Answer the name of the given camera. Answer nil if there is no camera with the given number." - - - ^ nil - ! Item was removed: - ----- Method: CameraInterface class>>cameraUID: (in category 'camera ops') ----- - cameraUID: cameraNum - "Answer the unique ID of the given camera. Answer nil if there is no camera with the given number." - - - ^ nil - - "CameraInterface cameraUID: 1"! Item was removed: - ----- Method: CameraInterface class>>closeCamera: (in category 'camera ops') ----- - closeCamera: cameraNum - "Close the camera. Do nothing if it was not open. Unregister any associated semaphore." - - (self cameraGetSemaphore: cameraNum) ifNotNil: - [:semaphoreIndex| - Smalltalk unregisterExternalObject: (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: nil)]. - self primitiveCloseCamera: cameraNum! Item was removed: - ----- Method: CameraInterface class>>declareCVarsIn: (in category 'translation') ----- - declareCVarsIn: aCCodeGenerator - "self translate" - - super declareCVarsIn: aCCodeGenerator. - aCCodeGenerator cExtras: ' - #include "cameraOps.h" - #include - '.! Item was removed: - ----- Method: CameraInterface class>>frameExtent: (in category 'camera ops') ----- - frameExtent: cameraNum - "Answer the frame extent of the currently open camera, or zero if the camera isn't open." - - | packedExtent | - packedExtent := self packedFrameExtent: cameraNum. - ^ (packedExtent bitShift: -16) @ (packedExtent bitAnd: 16rFFFF) ! Item was removed: - ----- Method: CameraInterface class>>getFrameForCamera:into: (in category 'camera ops') ----- - getFrameForCamera: cameraNum into: aBitmap - "Copy a camera frame into the given Bitmap. The Bitmap should be a Form of depth 32 that is the same width and height as the current camera frame. Fail if the camera is not open or if the bitmap is not the right size. If successful, answer the number of frames received from the camera since the last call. If this is zero, then there has been no change." - - - ^ 0! Item was removed: - ----- Method: CameraInterface class>>interruptDrivenVideoTest: (in category 'test') ----- - interruptDrivenVideoTest: camNum - "A quick test of video input. Displays video on the screen until the mouse is pressed. - Answer nil if the interrupt-driven interface is unavailable." - "self interruptDrivenVideoTest: 1" - "self interruptDrivenVideoTest: 2" - "[self interruptDrivenVideoTest: 2] fork. - self interruptDrivenVideoTest: 1" - - | semaphore height | - height := 16. - 1 to: camNum - 1 do: - [:camIndex| "N.B. the of an unopened camera is 0 at 0" - height := height + (CameraInterface frameExtent: camIndex) y + 16]. - (CameraInterface cameraIsOpen: camNum) ifFalse: - [(CameraInterface openCamera: camNum width: 352 height: 288) ifNil: - [self inform: 'no camera'. - ^nil]]. - semaphore := Semaphore new. - [CameraInterface camera: camNum setSemaphore: (Smalltalk registerExternalObject: semaphore)] - on: Error - do: [:err| - Smalltalk unregisterExternalObject: semaphore. - self inform: 'interrupt-driven camera interface unavailable: ', err messageText. - ^nil]. - [| f n startTime frameCount msecs fps | - [semaphore wait. - "N.B. the frame extent may not be known until the delivery of the first frame. - So we have to delay initialization." - startTime ifNil: - [(self frameExtent: camNum) x = 0 ifTrue: [self inform: 'no camera'. ^nil]. - f := Form extent: (CameraInterface frameExtent: camNum) depth: 32. - frameCount := 0. - startTime := Time millisecondClockValue]. - Sensor anyButtonPressed] whileFalse: - [n := CameraInterface getFrameForCamera: camNum into: f bits. - n > 0 ifTrue: - [frameCount := frameCount + 1. - f displayAt: 16 @ height]]. - msecs := Time millisecondClockValue - startTime. - fps := (frameCount * 1000) // msecs. - ^(CameraInterface cameraName: camNum), ': ', frameCount printString, ' frames at ', fps printString, ' frames/sec'] - ensure: - [CameraInterface closeCamera: camNum. - Smalltalk unregisterExternalObject: semaphore. - Sensor waitNoButton]! Item was removed: - ----- Method: CameraInterface class>>openCamera:width:height: (in category 'camera ops') ----- - openCamera: cameraNum width: frameWidth height: frameHeight - "Open the given camera requesting the given frame dimensions. The camera number is usually 1 since you typically have only one camera plugged in. If the camera does not support the exact frame dimensions, an available frame size with width >= the requested width is selected." - - - ^ nil - ! Item was removed: - ----- Method: CameraInterface class>>packedFrameExtent: (in category 'camera ops') ----- - packedFrameExtent: cameraNum - "Answer the extent of the currently open camera packed in an integer. The top 16 bits are the width, the low 16 bits are the height. Answer zero if the camera isn't open." - - - ^ 0 - ! Item was removed: - ----- Method: CameraInterface class>>primitiveCloseCamera: (in category 'private-primitives') ----- - primitiveCloseCamera: cameraNum - "Close the camera. Do nothing if it was not open except answering nil." - - - ^nil! Item was removed: - ----- Method: CameraInterface class>>trySetSemaphoreForCamera: (in category 'utilities') ----- - trySetSemaphoreForCamera: camNum - "Attempt to set a semaphore to be signalled when a frame is available. - Fail silently. Use e.g. waitForCameraStart: or waitForNextFrame: to - access the semaphore if available." - | semaphore | - Smalltalk registerExternalObject: (semaphore := Semaphore new). - [CameraInterface camera: camNum setSemaphore: semaphore] - on: Error - do: [:err| - Smalltalk unregisterExternalObject: semaphore]! Item was removed: - ----- Method: CameraInterface class>>videoTest: (in category 'test') ----- - videoTest: camNum - "A quick test of video input. Displays video on the screen until the mouse is pressed." - "self videoTest: 1" - "self videoTest: 2" - - | f n startTime frameCount msecs fps | - (CameraInterface openCamera: camNum width: 320 height: 240) ifNil: [^ self inform: 'no camera']. - self waitForCameraStart: camNum. - (self frameExtent: camNum) x = 0 ifTrue: [^ self inform: 'no camera']. - f := Form extent: (CameraInterface frameExtent: camNum) depth: 32. - frameCount := 0. - startTime := nil. - [Sensor anyButtonPressed] whileFalse: [ - n := CameraInterface getFrameForCamera: camNum into: f bits. - n > 0 ifTrue: [ - startTime ifNil: [startTime := Time millisecondClockValue]. - frameCount := frameCount + 1. - f display]]. - Sensor waitNoButton. - msecs := Time millisecondClockValue - startTime. - CameraInterface closeCamera: camNum. - fps := (frameCount * 1000) // msecs. - ^ frameCount printString, ' frames at ', fps printString, ' frames/sec'! Item was removed: - ----- Method: CameraInterface class>>waitForCameraStart: (in category 'utilities') ----- - waitForCameraStart: camNum - "Wait for the camera to get it's first frame (indicated by a non-zero frame extent. Timeout after two seconds." - "self waitForCameraStart: 1" - - | startTime | - (self cameraGetSemaphore: camNum) ifNotNil: - [:semaphoreIndex| - (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: [self error: 'seriously?!!?!!?!!?']) wait. - ^self]. - startTime := Time utcMicrosecondClock. - [(self packedFrameExtent: camNum) > 0 ifTrue: [^ self]. - (Time utcMicrosecondClock - startTime) < 2000000] whileTrue: - [(Delay forMilliseconds: 50) wait]! Item was removed: - ----- Method: CameraInterface class>>waitForNextFrame:timeout: (in category 'utilities') ----- - waitForNextFrame: camNum timeout: timeoutms - "Wait for the camera to get it's first frame (indicated by a non-zero frame extent. Timeout after two seconds." - "self waitForNextFrame: 1 timeout: 2000" - - | now timeoutusecs | - (self cameraGetSemaphore: camNum) ifNotNil: - [:semaphoreIndex| - (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: [self error: 'seriously?!!?!!?!!?']) waitTimeoutMSecs: timeoutms. - ^self]. - now := Time utcMicrosecondClock. - timeoutusecs := timeoutms * 1000. - [(self camera: camNum getParam: 1) > 0 ifTrue: [^self]. - (Time utcMicrosecondClock - now) < timeoutusecs] whileTrue: - [(Delay forMilliseconds: 50) wait]! Item was changed: + ----- Method: EToyVocabulary class>>allPhrasesWithContextToTranslate (in category 'accessing') ----- - ----- Method: EToyVocabulary class>>allPhrasesWithContextToTranslate (in category '*Etoys-Squeakland-as yet unclassified') ----- allPhrasesWithContextToTranslate | etoyVocab results literals additions | results := OrderedCollection new. etoyVocab := Vocabulary eToyVocabulary. etoyVocab initialize. "just to make sure that it's unfiltered." self morphClassesDeclaringViewerAdditions do: [:cl | (cl class includesSelector: #additionsToViewerCategories) ifTrue: [ literals := OrderedCollection new. cl additionsToViewerCategories do: [:group | literals add: group first. group second do: [:tuple | literals add: (ScriptingSystem wordingForOperator: (tuple at: 2)). "wording" literals add: (tuple at: 3). "help string"]]. literals ifNotEmpty: [ results add: {cl category. cl class. #additionsToViewerCategories. literals}]]. cl class selectors do: [:aSelector | ((aSelector beginsWith: 'additionsToViewerCategory') and: [(aSelector at: 26 ifAbsent: []) ~= $:]) ifTrue: [ literals := OrderedCollection new. additions := (cl perform: aSelector). literals add: additions first. additions second do: [:tuple | literals add: (ScriptingSystem wordingForOperator: (tuple at: 2)). "wording" literals add: (tuple at: 3). "help string"]. literals ifNotEmpty: [ results add: {cl category. cl class. aSelector. literals}]]]]. + ^results! - literals :=( self allStandardVocabularies - select: - [:aVocab | aVocab representsAType] - thenCollect: - [:aVocab | aVocab vocabularyName asString ]). - results add: {Vocabulary class category. Vocabulary class. #typeChoices. literals}. - ^results.! Item was added: + ----- Method: EToyVocabulary class>>initialize (in category 'class initialization') ----- + initialize + + self addStandardVocabulary: EToyVocabulary new. + self addStandardVocabulary: EToyVectorVocabulary new. + + self addStandardVocabulary: PlayerType new. + self addStandardVocabulary: ScriptNameType new. + + self addStandardVocabulary: (SymbolListType new symbols: #(lines arrows arrowheads dots); vocabularyName: #TrailStyle; yourself). + self addStandardVocabulary: (SymbolListType new symbols: #(rotate #'do not rotate' #'flip left right' #'flip up down'); vocabularyName: #RotationStyle; yourself). + + self addStandardVocabulary: (KedamaPatchType new vocabularyName: #Patch; yourself). + + self addStandardVocabulary: (SymbolListType new symbols: #(wrap stick bouncing); vocabularyName: #EdgeMode; yourself). + self addStandardVocabulary: (SymbolListType new symbols: #(logScale linear color); vocabularyName: #PatchDisplayMode; yourself). + + self addStandardVocabulary: (SymbolListType new symbols: #(#top #'top right' #right #'bottom right' #bottom #'bottom left' #left #'top left' #center ); vocabularyName: #AttachmentEdge; yourself).! Item was added: + ----- Method: EToyVocabulary class>>unload (in category 'class initialization') ----- + unload + + #(eToy Vector CustomEvents Patch PatchDisplayMode EdgeMode AttachmentEdge Player ScriptName RotationStyle TrailStyle Wonderland) + do: [:vocabularyName | + self allStandardVocabularies removeKey: vocabularyName ifAbsent: []].! Item was changed: + ----- Method: EToyVocabulary>>systemSlotNames (in category 'initialization') ----- - ----- Method: EToyVocabulary>>systemSlotNames (in category '*Etoys-Squeakland-initialization') ----- systemSlotNames "Answer a list of the predefined system slots" ^ (methodInterfaces select: [:m | m resultType ~= #unknown] thenCollect: [:m | m selector inherentSelector]) keys " Vocabulary eToyVocabulary systemSlotNames "! Item was removed: - DataType subclass: #PointType - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-Protocols-Type Vocabularies'! - - !PointType commentStamp: 'sw 2/8/2012 17:57' prior: 0! - A value type whose representing Point-valued variables.! Item was changed: + ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category '*Etoys-defaults') ----- - ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category 'defaults') ----- addExtraItemsToMenu: aMenu forSlotSymbol: slotSym "If the receiver has extra menu items to add to the slot menu, here is its chance to do it. The defaultTarget of the menu is the player concerned." aMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym. aMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated! Item was changed: + ----- Method: PointType>>defaultArgumentTile (in category '*Etoys-defaults') ----- - ----- Method: PointType>>defaultArgumentTile (in category 'defaults') ----- defaultArgumentTile "Answer a tile to represent the type" ^ (0 at 0) newTileMorphRepresentative typeColor: self typeColor! Item was removed: - ----- Method: PointType>>initialValueForASlotFor: (in category 'defaults') ----- - initialValueForASlotFor: aPlayer - "Answer the value to give initially to a newly created slot of the given type in the given player" - - ^ 0 at 0! Item was removed: - ----- Method: PointType>>initialize (in category 'defaults') ----- - initialize - "Initialize the receiver" - - super initialize. - self vocabularyName: #Point! Item was changed: + ----- Method: PointType>>newReadoutTile (in category '*Etoys-tiles') ----- - ----- Method: PointType>>newReadoutTile (in category 'tiles') ----- newReadoutTile "Answer a tile that can serve as a readout for data of this type" | aTile | aTile := NumericReadoutTile new typeColor: Color lightGray lighter. aTile setProperty: #PointValued toValue: true. ^ aTile! Item was changed: + ----- Method: PointType>>wantsArrowsOnTiles (in category '*Etoys-defaults') ----- - ----- Method: PointType>>wantsArrowsOnTiles (in category 'defaults') ----- wantsArrowsOnTiles "Answer whether this data type wants up/down arrows on tiles representing its values" ^ false! Item was changed: + ----- Method: PointType>>wantsAssignmentTileVariants (in category '*Etoys-tiles') ----- - ----- Method: PointType>>wantsAssignmentTileVariants (in category 'tiles') ----- wantsAssignmentTileVariants "Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by." ^ true! Item was changed: + ----- Method: PointType>>wantsSuffixArrow (in category '*Etoys-defaults') ----- - ----- Method: PointType>>wantsSuffixArrow (in category 'defaults') ----- wantsSuffixArrow "Answer whether a tile showing data of this type would like to have a suffix arrow" ^ true! Item was removed: - RectangleMorph subclass: #WebCamMorph - instanceVariableNames: 'camNum camIsOn frameExtent displayForm resolution useFrameSize captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps orientation' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-MorphicExtras-WebCam'! - - !WebCamMorph commentStamp: '' prior: 0! - INTRODUCTION - ========= - - WebCamMorph together with CameraPlugin (originally from MIT Scratch) provides an easy and cross platform way to use webcam input in Squeak and Etoys. The first version has been created specifically with Etoys in mind. To view a live feed simply drag a "WebCam" tile from the "WebCam" category in the objects tool. Open up a viewer on the morph and display the "camera settings" category to explore the following basic settings: - - "camera is on": turn the camera on/off. - - "camera number": usually the default of "1" is ok but if you have more than one camera connected then adjust between 1 and 9 for other instances of WebCamMorph. - - "max fps": leave as is for now. It is unusual for webcams to capture at higher than 30fps. See later for further explanation of how fps is controlled. - - "actual fps": read-only. Indicates the actual fps being achieved which can depend significantly on lighting conditions and capture resolution... - - "resolution": webcams can have a range of resolutions but for simplicity three are supported: "low" (160x120), "medium" (320x240) and "high" (640x480). Adjust in good lighting to see if "actual fps" increases. - - "use frame size": the resolution used for capturing can differ from the resolution used for display. If this setting is true then WebCamMorph is resized to match the camera resolution. If false then you are free to resize it however you want (via the "resize" halo button, use shift to preserve aspect ratio) - - - Beyond viewing a live feed WebCamMorph has been designed to support different uses including simple effects, time-lapse photography, stop-motion animation, character recognition, motion detection and more complex processing of every frame for feature detection. The following information is to help you understand how and why WebCamMorph operates so you can adjust it for your particular needs. - - - "FRAMES PER SECOND", LIGHTING & CAMERA RESOLUTION - ================================== - - The maximum possible frame rate depends on many factors, some of which are outside of our control. Frame rates differ between cameras and usually depend significantly on chosen resolution and lighting conditions. To ensure a balance between capturing every available frame and keeping everything else responsive, WebCamMorph dynamically adjusts the delay between capturing one frame and the next (does not apply when in "manual capture" mode, see later). - - WebCams often include automatic compensation for lighting conditions. In low lighting it takes significantly more time for the camera to get a picture than it does in good lighting conditions. For example 30fps may be possible with good lighting compared to 7fps in low lighting. So for best capture rates ensure you have good lighting!! - - Cameras have a "native" resolution at which frame rates are usually better than for other resolutions. Note though that the native resolution might be *higher* - than the *minimum* resolution available. It pays to experiment with different resolutions to find which one results in the highest frame rate. Use good lighting conditions when experimenting with resolutions. - - - "MANUAL CAPTURE" MODE - =============== - - In simply usage WebCamMorph automatically captures a frame and displays it. To support Etoys scripting a "manual capture" mode is provided where you or your script determines when to capture, when to apply effects (or not) and when to update the display. In between these steps you can do anything you want. Note that frames rates will be lower than that in automatic capture mode and that "skip frames" (described next) will need adjusting at very low capture rates. - - Tip: In manual mode the camera can be turned off. It will be turned on automatically when required and return to it's previous state after a frame has been captured. For capture periods of five seconds or more turning the camera off may save power, which can especially useful when running off batteries. For smaller periods leaving the camera on will avoid some delays and could help speed up webcam related scripts. - - - "SKIP FRAMES" - ======== - - Webcams and their drivers are typically designed for streaming live video and use internal buffering to help speed things up. At low capture rates the picture can appear to lag real-time because what you see is the next available buffer not the *latest* buffer. So for example if you capture a frame every ten seconds and there are three buffers being used then what you actually see may be thirty seconds old. We have little/no control over the number of buffers used and the actual number can vary between cameras and under different circumstances for the same camera. "skip frames" is provided to compensate for buffering so increase it when doing "manual" capturing until you see what you expect to see. Typically a setting of 8 is enough but I have had to use 20 with one particular camera in low lighting. - - - "SNAPSHOTS" - ======== - - Where as "capturing" is the process of getting an image from the Camera into Squeak/Etoys, a "snapshot" preserves whatever is currently displayed (which may be the captured image after effects have been applied). To store snapshots you need to designate a "holder" which at the moment can be either a "holder" morph or a "movie" morph. Create one of these before proceeding. To assign a holder open up a viewer for WebCamMorph, display the "snapshot" category and click in the box at the right of the entry called "snapshot holder". The cursor will now resemble a cross-hair and can be clicked on the target holder/movie morph. To take a single snapshot at any time click (!!) on the left of "take snapshot". In auto-capture mode WebCamMorph can also be set to take multiple consecutive snapshots . First, before turning the camera on, set a sensible limit using "snapshot limit" (to avoid using all the computers memory) then set "auto snapshot" to true. When the camera is next turned on then s napshots are taken for every frame until "snapshot limit" becomes zero. "snapshot limit" is automatically decremented but not reset to avoid problems (although you are free to reset it manually or via a script). - - - "EFFECTS" - WIP - ========= - - Similar to snapshots, a holder can be designated as the "effects holder". This holder is intended to be populated with "fx" morphs (coming soon) which will operate on captured frames prior to displaying. Stay tuned ;-) - - - CLEARING SNAPSHOT & EFFECTS HOLDERS - ========================= - - Keeping a link to snapshot or effects holders can tie up resources even after the target holders have been deleted and are no longer visible. To ensure this does not happen designate the WebCamMorph itself as the holder (for method see "snapshots" section above). - - - COMING SOON!! - ========= - - - Built-in basic effects such as brightness, contrast and hue. - - Image "fx" morphs for effects such as those found in MIT Scratch and many other types of effects/ image processing. - - More snapshot options, eg, store to file - - Demo projects - - ! Item was removed: - ----- Method: WebCamMorph class>>additionsToViewerCategories (in category 'scripting') ----- - additionsToViewerCategories - "Answer a list of ( ) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories." - ^ #( - - (#'camera' ( - (slot resolution '160x120, 320x240, 640x480 or 1280x960' - WebCamResolution readWrite Player getWebCamResolution Player setWebCamResolution:) - (slot orientation 'Natural (mirrored) or navtive (as from the camera' - WebCamOrientation readWrite Player getWebCamOrientation Player setWebCamOrientation:) - (slot cameraIsOn 'Whether the camera is on/off' Boolean readWrite Player getWebCamIsOn Player setWebCamIsOn:) - (slot useFrameSize 'Resize the player to match the camera''s frame size' - Boolean readWrite Player getUseFrameSize Player setUseFrameSize:) - (slot lastFrame 'A player with the last frame' Player readOnly Player getLastFrame unused unused) - (slot showFPS 'Whether to show the samera''s frames per second' Boolean readWrite Player getShowFPS Player setShowFPS:) - )) - ) - ! Item was removed: - ----- Method: WebCamMorph class>>allOff (in category 'accessing') ----- - allOff - self allInstancesDo: [:each | each off].! Item was removed: - ----- Method: WebCamMorph class>>descriptionForPartsBin (in category 'parts bin') ----- - descriptionForPartsBin - ^ self - partName: 'Camera' translatedNoop - categories: {'Multimedia' translatedNoop} - documentation: 'Web camera player.' translatedNoop - sampleImageForm: self icon! Item was removed: - ----- Method: WebCamMorph class>>icon (in category 'parts bin') ----- - icon - "Original file: imagecodericon.png" - - ^ (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: - 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAA - CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wIECy0ZfllfzgAAAB10RVh0Q29tbWVudABD - cmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAgAElEQVR42uW7yZNsV37f9znDnTOzMrOGrPHh - oR7mBtAC0BPAbpJqEpQ4tNkSF3JYbdMOLWhHmOEI/wE2rFCEubFX3lgOO+wQg3bYEbQtyaRE - kGx2mw12kw00UOjG9F7VG+rVkDXkeO/NO57jxc33RMlaOGjvfHKRmXc4957fPHyP+Dv/zj/E - sdhagBYGi4MUFolFIkCCxGIRSAwIiUCCAOzynBCAQNm6uUtUWCTWSoTNUEgqdHOLfTRbCbam - RpFkKZ6nUQgMCmyJNGCExVpBbS3SGmorELYGSoy1CGupLUhbUloJFszyY2uohUEYS2UBarCG - wkgsIGyFsUZojbRGShQgmvUiEGhoFokAFFIYpBXUQiKxCGGQFuzyv0GBUGByhHARGIwpSIuS - dtBCGwXUGCqsUFgcjHBRtsZBUywKoqCFFBZhFIYKZfVjwhs0ippHbyix1ABIauEgLECFxCBs - hRVgLYBFixprGiao5VVWgMVYDQ6KZvUKg6DhKlIgl48DgUWjhEFhG7pYgRUSjcBikLJGGkuF - beZDkBUZ8eyalhdRlTEC0I7PxeiM3kqPoqxx3YiqzkizGLCsBC0qKaA0CCkBBcKiqBsiYxHW - wYoKg2iOGIm1AgtYKkrhNdIpDJYKYxWCumGlsAhbUyGRgNYIpBAI7HKxEiXA0nBWCttw2QqU - kA0XhUJhANlQXgiEtRgMZVkjVEpRg60LlK2Zzy6oqoLuyiZlWTKbXSAxeG5IWlRkWYanFZ52 - QGjmkzOEgDDwwBYIYRHSRS7F3oqaGom2GqippMDaRn0NEtcajKgwVoBt2AHgILBU1Ev1NVai - lZCNbi8pIgQIIUFKpAGExcFihGhURAgU9rFcIFhyxzJLZmBKLscz8ioj8kOqyuBqn9n0iqLI - KaqS4fkdiixlc+MGV+NzHOkQ2xzX8UC7aKk4v3zIk0+sEsdX+F6EK10QAiNV857WYoWlRqNZ - ijxgoBF1C5ICKy1YSy0bRRXmEbMVyAopRSOyWliUACUaCXCsQUvQAqQERxq0MEghkEiUkIgq - BVNhASksgeuySFMUFbYqUNLB1CUtP2Rz7QlG4zPydIKQBmtKTs8Pub6+x2h6CqYkTWY8PDsE - BHsbW8wn51RFxWg8BGq0AFdWCCGRj5gkDA4GJcWSORIXs7zGQ+IihUQh0VaiUDi2+a2RaEmz - wEb3xVIJQEiLwGIBhcCKxjgKDGU5o6wsk+k5SrlEviYMutR5ChhGk3MCNyJfzFGipqoLfM9F - K5duu890dkGezVnkCVWdM48nbHQ3efDwIzqtNYoiazyBkCRZwqC3g5Ye2haUVi91W6JsI4VW - iMbjCNNwG3AaX4BFIIBqadCNhUq4SFsBoJVkabQatydFI9ZFkVOWC9phCyldhGgmSpIpR/d/ - TLc7IJ5PUMphNitZ6WR4TkgcT5jPr1Adje8HXIwvaUc9JtNrdtc2OXr4Ma52OLs+pt/qc3Jx - j+2NZ5inY3ylqcuUdDFllgwpixypFIPVHYQtQEhcaowFI0xjjqWiQqKoHou6tBZhDLUQGGPB - SrQwGKuQ1CBKrBBIC+r1V/7WW1I0oi6URC5FvioWXF+fEkVtfO0iqUmTGXmRcXZ+iKM1ZTFD - Cpd7Jx8RxxMc7aNsjudFFEXCfD7m+PxjrmdD+p0+dW1oeS1m8ZjpfIhUCoVlkceMp+dEUZu8 - WOC7HvFihrRwNTppRFsI+lEPgUQLixCWLJsihcB9ZL8AtZQOxCNpNs0ZIUGYxk3SSDcIpFrq - vhCicXNLmxAGEZiS+fgSCSySGKqClh/R66wSuS5aaabTM4TJOb28w+XoHoEX0o1Wmc0uOR5+ - ylp3hyydoRHMZ1dIoBVEtPw2UNHvDMiLFN8NKPI5eRajpaTltijrnCjoMJmeU1YFQoBDSVXO - mUwvWSySJiCSoKRFSIEUEkfUuFhcajTNurS1zW/AEQIlNFqAVkIg5FL/xTIAMjVxnhLogNB3 - GY/PqKuKukjprQ7otlYpyhRfubitLteTh7hSMb4+pi4yJAYpNRu9deqqwpic0+EhWvkoDKEO - cLXDZD5kc3eT46EhcgKm8zFrK1ucX92jHXYwVY7jKOrasN3fwFeSqqwYja65ml3Q767SUgKE - xRqDEBprLYgm0JG4CFmBlVgJ1jTnKmwTqFGjvvbq336rsf6NLZBCohRUZUEcT4njMdPpBVJY - LkZnFMWCPI1RWjKaXBEEAZur27ScFq52UBLKfMFad51FNsXVDtP4ErC4Ggb9XXbW9ji/uk8Y - tJjGUwLPxwiLVopeq8/V5JQsT3Edj+l8RDvq4iqP0PNBaLI8JcnGVKZmFk+IXI1GNMZcNqG6 - xiKpEcJipUSbZQBHoz5N0G2QjftrQkstLBqLIwT9Voubm0+glWTQ26KuYm5t3+L0/A5Iw/X4 - go3uCot0xjwZE0ZtQrdFWS6acKPKGaxs4igXR2usKZknU1yt6LU6+MrHc1xGsyGzZEw36NBy - QtLFGK01Hb/DbD5id32fyA3whebq4kETUdqSoki4uLjPeHrG8dk9FsUCIQRagCMMUoKWAo3C - txWOBEc1a9NC4gqJQqMf6bxYuj8pl+GwkHQin5dvvcTl+JyyiLi4PmGwukm3tUKxmHNycY/9 - radJ85ittU2uhGCWXFDZnNOruzjKxdoaRzi42seRikF7jXQxYX11lSxbgKjZXbtBVWTUpiZO - p4RuSOD5VKagKjMQhrPRPbZWb1DnKWk6pswykmxCKwg4vbyP6wZsSkEr6oK0YAwGqJXFGNV4 - CCtQyqCsxViJEjXq577wzbe0AC1ByiajE0qghQVrsKZGAaVJKRcJiyKl47fxPAdpJdZWTJMR - ZZUx6G7iSoWQNU8NnsbXktpWlFXOjY09snyBi0ucXbO3sc3xxSGB26LthjjaoaJiHDeGshNG - zBdzZukEsIRuQD9skS1S0sWMvExJypg4S1jr9HGlizA1i0WMIw2OUkglcaARdcEylwEl6ia5 - w6K1oElwpEAIQ5WVuNJBWnjw8Ihuq8UiqxClYLXXo7zKuJpc0otcZsmUss4xdUboubQ9h0R7 - YAxX8yGBdmnrkGF5wmR6xXwx4Xh0xLO7+yTzKXEWo7XDRmeNoig4m5wyjScEXR9hJL7jYUzN - Wtgjy2fcPvmUyIsYxZdcxRM810FYhWmvkmdj3nv4Y3Y3bjC8hhf3X6ItQyoJ5lGwbgRI0YTK - dY1RNdp55AaXkWBexDw4HSKVRBrLw7MjdreepBV1uJ6coZSlH4RM4xFrgU9mHKZpSpbOGE8u - GHR7dALNdz7+HqtRj7ossLZif3WX3zv9iEWR4GDwgogb3W3uX58QxxPSKqMfdHhgDD2/TWUW - hL6HwLDie8xyQ1UVTOMFpoa0mBP5GyihMLYmSSbE+RhP3aQoFtRZiuOHaAtG1djaUisLpqkv - NFohUb/05V99S0lw1NJ4CIGUEqEsrdAn9AMm41M67ZB2GOIKwyyZ8tz2La6nF4znVyyyBEdK - 7p7fIXAUW911bnQ3OZ2c4TmKk9GQMAjJ8pzQcYlCn4fXD6nKglf3X8BFIxQ8GD3kmc2bICX3 - Lx6w0V5lu7+FsSVX0wvWW32m2RSLYbyYUpmKylTUVcE4HSMEJIuUtVaH0A1YaXVwl7GBlGJp - 5E2j6tgmzf43vvyrbzlS4GDR0uC7DqHjoAV0oxDqgpVul8n1OdViQTsIuD+8hyfBmgrX0fSi - DmkxZ5RM6YdtIsej31vhfHyKL33W2n1Oxhf0/BYPRycE2iHwAna66+xF69xYWyMUko+Gd+j4 - LR5cnvDKzeeR1nJ69ZBaQNePaLsBtiq5jK9pBSFaCF4Y3OIyGYGtWQm7hK5GW4GWkp3+Gq5W - aGnRsEyYmqhXLb+1Lw1SNimxpMn4XMdyfO8+4eYWg3aIp10iUzNfzEizhLxaEAU+T63uMk5G - 3B7eZ6Pdp+9HjJMRq60VeoXHemeFjtNivb1K9dmfc+fihMDxuHP5gBsrm8x1yMyb4juSOxf3 - qA0MZ5e4jiKvcrbaHS6mV3R8j74KyaqCnU6fu/MLpDVsdda4Tsa0HYdZluJhqIuctf42HjUu - NZ5svJsVYKyhXn5bYzGA+jtv/MpbjgRXGHwloS5ZJDMklvfvfEjkeswmlyghCTXcXN/k5d1b - /MmP32E+n7HZ7fP01i5SSm50VzHS8uLOPi3fI88WzNMFz6xu8PDyIVVR4TseJ7MRT3f7CCu5 - udKjqzU/vrjLVTzm5uoAW5aMkxkv7OwDhtDxeGp1i6LKmeUJJSWOdhhEK0SeR1HmFGXBatjG - mhpBzVee/jwtz4UyRguL6zRBmjIlWoMSjUqov/tT33jLV+Zf6IetKRYJVZYQKknX83CEoCxm - FGXJs9vbpEnMiutzdPWQqlpwdHaPQMD+1ja9MGJRxmxGbZJswV/c+YDQwuX0kid7A6yjuH35 - EMf1eXF9k9PJJVIKPro85rUbt1j12/zk7AghLWWWk9cFz/c2uTc+Z80NOLi4h9IKH8l1Nqcy - FdbUbLV6SGNouQ6rXoteELLiOSySmLJc0I0CsmTGLJ2xEgS4SqCUQEYSAqlwTEWVJbi2YHOl - jY/BGENRpjx3Y4/nt3fZ6XW4fe8Tyjpj0O7wpZv7nCcjWqGHq2CaTLkaDbl9/zYulhutDl/b - f44fDY/Qrssbt55jMR+x3e7ytSee4cfDB0Seyx/eeZ8vbN1AmMY/f2H7JoF06XkO2tZ8NryP - omIaTxFSEiI5T8b0XZdt6fLKxi55lZKbjMBx0LagymNG1+fE8TWT6TVUOapaEIkaX1kCDYEG - 9fd+plGB0NFoBXmaoJXA8TTClrQciawrrq6HPDHYZDqf4inBPJ3yzGCTLoLj8SVP9weIPOWJ - tQ3SPOeT40Oe7/fZ669wGU+Y5SkPL05JTMXh9ZCNbpcimfPj61Ne2drjfHxFUqUUZYWUlo52 - OYvnKCFouS7D+ZhZPqfn+Pzo8pgv7ezzQm/AzY0BabYgr0u2W108a/jcYJet9grHlw8RdU1c - ZWyELe6e3acXBgy6XbS0uBh0IC1aCKS0hI7LeriBsDVJbNlducU7H/wAbS2yLkimV/SUxKfG - 1YrT4we0sfybL73Gf//n32a6WPDqzpP0gpDzMiVPZuSzmj6aOZINz8cYQ1WVzGZTtjsrSMfh - 8701/qvDj9jo9XhxtcNuq829yYSXNrf4zuEnfFLl/PTuk1RVzZ+ePWA9iHClpRt6mKLk0+tT - nt/YJjCCjIKr2Yjjy4coxyFyHZ7qrfHg9AGDlR47a2sECmorqaVF/eZf/5W3PAmuErhS4Uvw - lKIqM7J4xvZKl1k845PTQ165cZNeOyLwAgKt6IYO4yRhOLrki3s3+OnnX+Sz82NO59f88N4R - n9vd4SvPPo2rNR+f3OfW2jpPr65xd3LJ5/sbfDYe8eLaGnVdMC1yvvHs8+y1Wvzw5Jjb4wu0 - gJ+78SQHF2eUxuC6DkVV8sbeTb564wk6QYt37n3KRhCx3+5ye3jKMJ1xEU+Y5QtCz2Oj28VW - OcpzeWFnB1drAtfBlRIpQf1HX/uFtxwl8ZXCU01AJIWlLhLmoyHnl+coUzOfTbl9ecbmSpfp - 9Tmj6RSpFVW+oBv6XM8mrGjJ87t7PLO2xsu7N/jdd7/P1mCbvEp5dvcG/+zDD3hqpcP3Tx9C - bZBaMZqO2dre4u//4q/w/mef8s/uHvELzz7Hz27v8cnogn9+7w43+j3+3dff4KX1DT69uGS7 - 1eZ0MuEnl6fMFgl7q6t8/eln2Ah8Pru+xHEUu2FIoAS7vT5Swl67Rb/TphOFBK5EKnAVaGVL - AsdFK4FUIKyhKjI8JfA9D6UNx1dDtgZrlEXGj48PeWZjg/l0xGV8Teh6jPI5/cCnMiU7qxGz - i4wnb+5y93SP3/vB9/hbr77Ca6++TJol3L+8pipKBqs+f3B8j19+8XP86v5T/N4Pf8A/PbyN - pzWfXg55dn2Nw9E1rz9xky9tbfHkxgb/+T/5xwzTmM3EY73b5c39Z3my3eLo4Ql/cPAeZ2nM - zVbE3SSmF0T0eisM+h12+32kqbHSUlcLWuFK0zuwoP79L3z5rVbooaRFO5IyHiFEjSlTtK1I - rye0PU0r8FgUJZ4j+f6dO2z3O0SeQxLH+FJSiBrlOMRxyuDpJ5CO4tUndvj9d3/E3/u3/jbJ - xTnrQvPe4R2MqQlaEWeTGYFyOE+mnM1TfutXf5kbvsu//dUvcTGf8+3PPuM/+eVfpCgL/ss/ - /iO+/sxT/Gd/829w//QMV0rKquDe+Tl3x2NOkjkvDdb5yv6TTEZXjBcJL+1ss+EqFumUzY0N - gkDT66+hXYHWEqUE6j/8wlfeWumvUGYpxmTMry6RWiERJNMxg0GfVhRSmop2d4W6KMjqnLwo - +NzNGzy1O+Dh1TXrg1XC0EeYgifX+6Aknz084fbJGT/1wrOY6yu07zFJY/74s7ucxTF//xf/ - BhUG8oJfe+VFHM/Bk4L/6d0D/ocf/Dk73S4nSco/evcvuNHtcj6f8979Y3ZXe7xxc4+B5zZN - O9flZ3c2KfMCKwWfXV7wTK9HMZ/w6fU1G0HA9fiaTuDhtyKUo5tkTwh0kU6g6BK1Q9I0JS0X - jE8mtFsReRFT2YoHp+d4gcdaN2LF6fDMzio/vH2XP//4U9aDgBtrK5TADz7+lJYfcng15rUn - d/nw6IhxuuDO0T32dzfo9Xr82s0d3r13zIM0A1ey1vJ589WXKX2HoL/Kx6Mr3v7kY0ZpwtO7 - 28yTOa+srvGzN3dZdTx29rYZXU84vb5m0G5xOZnw2pM3qdOMpzZX+fjskrVWxI/PzqiswdUe - sip549lnubwaobQGDK31Laraon7zi6+91e608FoBbhjgCKjqisl4Qif0CLtt1ntdopYPdU2J - ZTKPafkeoqrITcXO0/tMT4eUdcVsseCFZ27x4Z0jji+uEVh2Vnvo8ZTJyTntXofRdMp3Pzsi - Kwt+81e+Tr/fZn2wxvuf3uEff+8HLGrDRiviP/jGm1STKT+/u0XUDrl/fsHh6TllVXIj8HFt - zXlWshr4UJU8WOTcubzk2dU+z20OeGV3h0CARuL7EXlZ4GgXN2wvgzyDuPsn37Z5nqN9nwfH - x+xsbyKtxXMkWZEjtQLThMpCK6SgqbzamlmaEgUeVVlRFjlKSqJWwOX1CF9LxklCWpTsddso - a/B9F6kl5+MJV7OY9W6b7V6bui4ZzRPSPEMYw1WSMOi0kEKQ5hlVWRK5DspUuFqRlSWVtSRl - Tktpeq2IcZoQuJosy/BdtymJmWpZ3hN4rosBsBbXdXEcF2tBHz94wOdffomo2+bJm7sIAWW2 - aNqnwmLrkqoouLy6Ip7M8H2XwdaARRyjpc/qWp+6KqmKHGkNaMlKa8DZ5RVd6eMWAu3CE1sb - FHlT98syQVZLViOBFgWXsxGdwKUXeJxOJnQCCH1LVizY7bq0XZ/ZYsFlkrGoa0JXgTU82fEp - 64pFOcLVNZHnIykItaE2FfmScIuyQKLpBiEI8FyFVAV1VaHBYkzNu+++S3dlhfXVHmEY8tY/ - +C22tgb8tZc/xxuvf4GTHw/5H//n/41v/uLX+d6f/QV7N3c5v7hisNrl4KNP+dnXX2U6nZEl - Czr9DkmacvjghNB3iWdz9rc3iOcxYeTzv/z+n/Lrv/5LnE9jAlfzxMYaaZ4xTRKUUpRFTrxY - 0PFcitpwnZcsipJ+EFJh6Houi7JgukhZ8T08J2SyWJCVBd0oIitzlNSEWqKFZEVJpNQIAVo1 - UlzXNcYYZJomGFvRikLe/pPv4gYBytU8/exTfPWrX6asa6q64ktffIWbT+wQrbTxIp/LqxF3 - 795neD1io7/C//5P/4hPPj3kejzmu9//ET/zlc8zPLvk8y/c4qPb9/mLH31CVlZo3+OnvvgC - jtb02i1ubW9wMZkxmsckWYYFXtgasN9bYdCO2F3rE2rNahBQY+mFIcYYLBB6LnldM8sWrLci - Wq7LoshwpaLjB3Q9n07gEfk+SjbNXakUlqYHIaRA/cf/3q+/tbbWw0rJl7/8GlorHEexSFMW - acr+jV3agUddl0gpuXnzBhtrfTrtiHY7Yv+JHXY31xhs9Ol0WziOw4vP3OTw8D4vPHuTXq9D - aQzHD4c8c2uP1197gbt3T+ivd1jkOXGS0vYc2lHIJE3Z73eJfJd4sSApcsqixNqaeZFTVBVt - V4MUXMYx7TCgHfj4jmYlDKiqiq7vo6wBa6hN/ZcAHCClXC5cYu0SC/HhP/lde+vWTfxWhDX1 - EvxksHUFtqaqmmOysSZISVN0WJaXbFVRJHPm8xgd+AS+y/jqCkeC0ppFXXE9mTa1wrUeVZkz - iWNOxhNWo4Ab612yLOOT0yGb7ZC8KnEd1WABlCB0HbSEO+cXrPkuQgrujkf0WhGOtRhqAsfB - kZBmGSuei6kqLAZHK7R2KIoCpVRTG9R62QURGGvR/W6L8Xvv4yGa/pqWWGMpFylCaTA1Siuk - 1gjHBSmwVckjElpjqPMMqTWzJOU0TkEI1td6lFlGnC44vxrTW2njrMRgDUcn51RAq9vh4qTi - 9oMTirqm8Ga4UhK5DmEUMs8LYldTFSXX44REZ1xnOW3PRXYUqbGs+i2UVtRVgVM7pFJSVzVa - K0ohQQry3MEYg+f7LLtj1KbBIOmyLHHjmM7Xf4FFVdJe6WCMbRYJfOePvs3+E/tsbG42RFCS - ujZYY1BKI7VECEEynxNWBl3VJFnOWVmhlcJ3NDtVRW2hN1glSVM64xlGSNpRwEWc0H7qFVqu - y8ZaH08IbF3iOy61kJRlSVlXOGnGPMt51lHUpWFcFjyztornuiilAcizHD+MKPIM7biNC6fB - CFjbgD2ssVR1TVUvCSCUoKxqvv0nf8w0nrO5vc0iy/GkYDadYeqaq8tLHjx8wMXVFSiFpzV7 - T93ic8+/QJkXoBVhFGLKgjwriQIPIQRpVXI+mtHrtLgYTZglKZHrIIWkrA2TRcaiqhi0I57Y - HuAFAaYoKXJFssjwPJeqKBsbMhqz1elQGktqDXsrK+Rlhev5y+gOpCwxdXMMAaY2CKmQUmBs - I63GGqRSOFJSVBV6Po/x8gXCD7ixs4Mb+rRaIY72WOn2uB5dsbm7RZwmdFb7tPpdHh7eBWNQ - CoQjsXWFMVDUBuW5OJ6LsDW6VqystLm6HFEZuJwn9HcHDbBKS3zXwdGK7dUeZVmxKOdUWYFW - EiUleVZwnSRcpCmR55NXNZvtNnFeUCOpMWRFzTydoZVGKU26KHHdprdpRINis8ZQW6itpaoF - VV1SLYmhq6riahrzxBffwFeKKPAxSiEsOAKevHmToNViSwrKLEdKxc3BTiNauaEqDVjIyqZH - oLWmSHPKosJzNY4UbPZXuY4XVLVhOI6XZXgoqhpTG4bXMxyl8B0X13EbqBeSOE8ZxinacegG - bSxwleaU1uDTJGzzIsEYQ+QFRJ7G8wOWEDbk0kYVRYF2HIQQOAr0UmWsBf1wkWEqwyqayzTD - y0o8R9MLQgoEH3/0E2azOVVtKKqKPFvwpVdfYzIZY61FSEUQhkghWFlZ4eDDA37qq1/j9//5 - H/L8s88xmU5IFwsmZc725hZFXXNxecGDkxOkkOwGEXs3nyCZTHj1lVf44OBDur0eH9++jbfa - 42R4zlbUQWxtMVhfp7SN/i7qBZ0gwpUKJSRxvqC0NaGp8bSDBVwJxixtvrV4SmAt1BZMg5dF - a6lYYJkWBTWQW9BWMi9qlICtW89w50//lMpUUFSs9Ve5fe+YLFsgpWx6/9cjTG0bXasb8jva - ZWtnl08+u8Pp2RmjdMbO9i6udrj38CEgmE0mrODw3f/zzyiLgvbagKtZQlzUHJ2fEx/fJ5vO - eebNN4lWVpjlOQLIyoLAcZFYyqrCSE0nCClrS2klSZriCIkUFq29JivEUFXmMRZOLKve4n/9 - 7X9o+eiI9Z/7BSQCrSQdLyArS1wl8bSmrg3dMEAKiVCK4fmQ8/MzvvSlLyHlEolpDVVdN8Aj - CaZuYoisLImLnEVZkhQFSghmRQ7AXrdH6HhorRvElta8//77rN+8QVzk9MM273/wAa3eCv3V - VWpTN2BJa9BKsxqtYI2hrMsl0R0C18cs8ctK6UYNrG3C3iWWsDI1RVlijEHXtsZdtouU1Kz5 - AVYIjJQNGtPU+FpjTMV3v/cOe3s32NveYmvjc7jSgqgacZICXwqKoqBaVE3kZCyhI5FGoa1h - ktX4vo8pMlbDkLUwQEmFkIraNNCVzu4WRV3S9X1sXbD/zC0AKtOgUR2h8LXGkZo4Swi0S2UM - jpTLdFcv0V8NMFYs8YFSSYy1lGXJosgwxlAvwaDYJexcW8PVIiWvKzyliRyX3/0/fo+vvPYq - 3V6f89GIMGoxPD9ndH2N42harYj1tXWef/55iqLA2mWvUWgq08DVXdfFYAm0ZpQmj2wUtTEs - irxBsVk4mc1YVBXPrK9j6pq0KOl7Lq6UXGWLpqdnK6yRRFqTVzXalmRVQcsPQEBIRWFqIlfi - Ok3sX1uLEA2WNsOgK0NhDY6j0MbWRFriqwYd7iiBtJKOEnRDzTd/+ivs7e02Fnxvk1tP7ZEt - FqSbPTprfS7OhwQtj9Zqq8Hgul4TZRnTqEZdUZYF0jisSsv0IkMAviPx1jqsaAVlxe0Hp2gp - eHFvq0mrS8PG+jpFmlGVBWDISsmkKPGFQNgSJSw9T9F2gybLsxZjKwIt8bVAaoHWAqFUgyY3 - NdJqFJpFUS5dtTFoLIomtl9zHXIpaAdNMLG2tspkOicMfV7/6a/iei4Yi1ASW9fs33oaUxWN - blY1dZYhZPM7Sxe4WuF2WmgktrbcvbjGAiudDqHrUuU5RydDamO4ubGGpxykViRlTLooyRY5 - YHEch2lWLHGBkmzZ3Z1VjTGTxuA7DTrFEQ5pZZq2uARbW4w1VFVFVVoqoyiARZmhBYZJUeIY - gy8l10WFtRDHGZVpABO+1tGZ8eYAAAbgSURBVMzjAjPLMECoHW7fuYOjNZPr6yb2X1+jqCqu - r6546ulnOD09pb+2ysbGBu/+/rfptNtkZUG0t8v58QkP3vsRX/nq1zgbXXH/3gPGDx/yd7/1 - LeqqRioorUMyy9COxySeUZia0sLCGKqySdAqYxjlJUKIRmVdhe/5TNIcRzuoomn1C9HsEjHG - YEzd7EKhIaI0WApjyOqaaVlytVhwnWWM85zaNgjSvK6pjaUyFmMsxlo+/PCAs7MzhsMhvu9x - cHBAPJ1SLjJOj+/TbYf0WxGB67BIYyZpzMnlJQb49PanxLM5cVkghGQzCtkcrHPy4AG+q/G0 - xnc0vqsQpqLlNnbAk4KW08BmXNE0c5QQBErTcX0cYfGExZMQOgppKqSpcKXBkxZfWlwBylY4 - GLp+iPid/+6/sHxyTP/rf7MxTkKgxRInbgUtrREW+oGPsGCW+zIixwVriTxvubXG4rkuOvCR - vtdkklJQpilSSoypSWZzfvjwjMViQbVYsLW5yV+7eQPXbbI1qdRjY1XnJcl0gnJcsmxBXtVU - xjDLC4SSZFVF6DhkZUVLO3iObup+xuB7AWVVopTCcRzkMv9/JAWLvEBIQV3XTUnsLw+7hJsr - IaisYVY2+p0njR+tTI1EEOqSw6O7vP7Sy5hluLW4GjMajXj66adxXRetFe9/cEBVG6bTCc+/ - 9CIW8IKAXrvNjfYK8XhOEIbNxiubo5RuKrZFQVIY4vmEyjZSV5oaiyDOcjypyGuDkRKrJHlt - mcUp3SiiqOtH2HfK2kK9DAeXqbDWmrTIqGuDbgLvf5kIxjbp4yNuAJTWYOrmuBKC77/3Hu8f - HPDZe++xt7PN1tYmF1dXhK7DYpGwe2OP7Z0dtnY3uXP7DtrV+IGLnTfz3equIE2NBJQjm6xS - SrQW2ArSMifJF6RlU4lSS53Xstl1JptUH0cIPCVZFBVCWAJH4zoO4hEm3Db+nqU6W5pKkS8V - Vmn0v7L2fyEJS2l49Mc+2jwhJaUxdNbXef6lFxEIfnh0xOt7e6jBFscXQ04ur5kol0xojk5P - SGYxo+mEaGfn8fzDJCEpSlwhsOMxxlgKa3GlXD67IbojBFVVUizVTwtJx9NYA5EjKYylqgrm - RUHXb7CL3TBAa73cySKwtsZY0ewiUQ1RkjIHaxG/89/+luXTU/pf/yX+3wzx+Hv5EY9oZ5fb - 1xrq/+vo/WinShwntFutJakFzS7A//tQy80bj6RVy2YniK8kEkFtDUpIXCXJ6gb6G7oaY6C2 - BldKKmNIKkNDyr/CePvtt7l16xaHh4fcutWEq8PhkMFgwObGJod3Dx+rz/BiyP7+PlEUMRwO - ARgMBgwGA95++20ODg548803GQwGHB4dEicxSZxgsQyHQ15++fOAJY5jXn75ZY6OjnjnnXd4 - 442fejzfm2/+POeTKQcHH7K5OeDw8PDx+wwGA4bDIVEU8cYbb/DOO+9wcXHB/v7+cqec/atx - fWNjgyiKOD8/5/z8nHfeeYeDgwP+4A//gA8++IDz4TlP7j9JGIYcHh5ycHDwePGPxuuvv85v - /MZvLMVH8sGHP2E4HGKxRFHEYLDJ0dEhcRyTJMlSUmK+9a1vcXR0SBSFDIfnjwlxcPABh4eH - j58TRRFHR0ePn/donm9+85scHR0hfue/+QeWz4b0f+6X+f9uCB7vrf1XqPuIK/+6EccJrVb0 - /+gJR0dH7O/v/5Xf8NH9jRew9jFlhsMhrVaLKIpIkoQoioiiiIuLC4DHxx/9/sscHQ6Hj+9/ - RIjBYJM4mZPEMRsbGwC8886fcevW/uP5H92fJDEXF8PHnGo42Obi4hyA/f19jo6OHp87ODhY - EkHQarUeS0GSxI+vaf4nbGxskCTJv/TuBwcHqF/7xl9/i+uEn4xmjMdjXNdlNBrx7rvv4jgO - Dx8+xPM84jimKIpGTw8bkXx4csrBwQe8/PLLHBwccHR0xObmJufn58RxwtHRIUdHh7hOU5vf - 29vj6OgI1/M5OrpHURR85zvf5bnnnmM8HvP222/z3HPPcXx8zHg8Zji84NNPP37sjQaDAcfH - x7RaLT755BOSJFleN2Rvb4/f/u1/xPPPP0dZlhwfH3NwcPD42kd2oCgKer3eY2apX/vGz7zF - dcr2a19+fMHm5iZ7e3sAbG5uPub6I86WZUm/32dvd5dWq/XY0CRJwmg0otVq0e/3iaKIvb09 - XNelKAqiKKIsS4oiZ3OwQasVcetWYxz7/f5jbrmuS6vVYnNz8JiLrVbTdXrEpH6/j+u6PPfc - cwgh6PV69Pt9xuMxRVHQarW4desWrusSRRGtVgshxONzQghc10X8zn/9n8LtK9v/+W/w/8Mh - /i957VpDfrfOMwAAAABJRU5ErkJggg==' - readStream) readStream) nextImage - ! Item was removed: - ----- Method: WebCamMorph class>>initialize (in category 'class initialization') ----- - initialize - "CameraMorph initialize" - - - - ! Item was removed: - ----- Method: WebCamMorph class>>resolutionFor: (in category 'scripting') ----- - resolutionFor: aSymbol - (#(low medium high hd) includes: aSymbol) ifFalse: [^ 320 at 240]. - - ^ {160 @ 120. 320 @ 240. 640 @ 480. 1280 @ 960} - at: (WebCamResolution resolutions indexOf: aSymbol) - ! Item was removed: - ----- Method: WebCamMorph class>>shutDown (in category 'accessing') ----- - shutDown - self allOff. - ! Item was removed: - ----- Method: WebCamMorph class>>startUp (in category 'accessing') ----- - startUp - "Try to bring up any instances that were on before shutdown" - ! Item was removed: - ----- Method: WebCamMorph>>addCustomMenuItems:hand: (in category 'menu') ----- - addCustomMenuItems: aMenu hand: aHandMorph - - super addCustomMenuItems: aMenu hand: aHandMorph. - aMenu - addUpdating: #cameraToggleString action: #toggleCameraOnOff; - addLine; - add: 'resolution...' translated subMenu: ([:menu | - WebCamResolution resolutions do: [:res | - menu - add: (resolution == res ifTrue: [''] ifFalse: ['']), res translated - selector: #setWebCamResolution: - argument: res]. - menu] value: (aMenu class new defaultTarget: aMenu defaultTarget)); - add: 'orientation...' translated subMenu: ([:menu | - WebCamOrientation orientations do: [:ori | - menu - add: (orientation == ori ifTrue: [''] ifFalse: ['']), ori translated - selector: #setWebCamOrientation: - argument: ori]. - menu] value: (aMenu class new defaultTarget: aMenu defaultTarget)); - addUpdating: #frameSizeToggleString action: #toggleUseFrameSize; - addUpdating: #showFPSToggleString action: #toggleShowFPS; - yourself - ! Item was removed: - ----- Method: WebCamMorph>>cameraIsOn (in category 'accessing') ----- - cameraIsOn - ^camIsOn! Item was removed: - ----- Method: WebCamMorph>>cameraNumber (in category 'accessing') ----- - cameraNumber - ^camNum! Item was removed: - ----- Method: WebCamMorph>>cameraNumber: (in category 'accessing') ----- - cameraNumber: anInteger - camNum ~= anInteger ifTrue: - [camNum := anInteger. - self initializeDisplayForm]! Item was removed: - ----- Method: WebCamMorph>>cameraToggleString (in category 'menu') ----- - cameraToggleString - - ^ camIsOn - ifTrue: ['', 'turn camera off' translated] - ifFalse: ['', 'turn camera on' translated]. - - - - ! Item was removed: - ----- Method: WebCamMorph>>decreaseCaptureDelay (in category 'accessing') ----- - decreaseCaptureDelay - - captureDelayMs := (captureDelayMs - 1) min: 200.! Item was removed: - ----- Method: WebCamMorph>>delete (in category 'submorphs - add/remove') ----- - delete - self off. - super delete! Item was removed: - ----- Method: WebCamMorph>>drawCameraImageOn: (in category 'drawing') ----- - drawCameraImageOn: aCanvas - | scale offset | - offset := 0 @ 0. - scale := 1 @ 1. - bounds extent = displayForm extent - ifFalse: [scale := bounds extent / displayForm extent]. - orientation == #natural - ifTrue: [ - scale := scale x negated @ scale y. - offset := bounds width @ 0]. - 1 @ 1 = scale - ifTrue: [aCanvas drawImage: displayForm at: bounds origin + offset] - ifFalse: [aCanvas - warpImage: displayForm - transform: (MatrixTransform2x3 withScale: scale) - at: bounds origin + offset]. - ! Item was removed: - ----- Method: WebCamMorph>>drawFPSOn: (in category 'drawing') ----- - drawFPSOn: aCanvas - showFPS ifFalse: [^self]. - aCanvas - drawString: 'FPS: ', fps asString - at: bounds bottomLeft + (5 @ -20) - font: Preferences windowTitleFont - color: Color white! Item was removed: - ----- Method: WebCamMorph>>drawOn: (in category 'drawing') ----- - drawOn: aCanvas - camIsOn ifFalse: - [self initializeDisplayForm. - self on]. - camIsOn ifTrue: - [(CameraInterface frameExtent: camNum) ~= displayForm extent ifTrue: - [self initializeDisplayForm]]. - displayForm ifNil: - [self initializeDisplayForm]. - useFrameSize ifTrue: [self extent: frameExtent]. - self drawCameraImageOn: aCanvas. - self drawFPSOn: aCanvas. - self drawOverlayTextOn: aCanvas! Item was removed: - ----- Method: WebCamMorph>>drawOverlayTextOn: (in category 'drawing') ----- - drawOverlayTextOn: aCanvas - camIsOn ifTrue: [^self]. - aCanvas - drawString: 'Camera is off' translated - at: bounds origin + (5 @ 2) - font: Preferences windowTitleFont - color: Color white.! Item was removed: - ----- Method: WebCamMorph>>frameSizeToggleString (in category 'menu') ----- - frameSizeToggleString - - ^ (useFrameSize ifTrue: [''] ifFalse: ['']), 'use frame size' translated - - - ! Item was removed: - ----- Method: WebCamMorph>>getLastFrame (in category 'e-toy - settings') ----- - getLastFrame - - - ^ SketchMorph withForm: displayForm deepCopy! Item was removed: - ----- Method: WebCamMorph>>getShowFPS (in category 'e-toy - settings') ----- - getShowFPS - ^ showFPS - ! Item was removed: - ----- Method: WebCamMorph>>getUseFrameSize (in category 'e-toy - settings') ----- - getUseFrameSize - ^ useFrameSize - ! Item was removed: - ----- Method: WebCamMorph>>getWebCamIsOn (in category 'e-toy - settings') ----- - getWebCamIsOn - - ^ camIsOn! Item was removed: - ----- Method: WebCamMorph>>getWebCamResolution (in category 'e-toy - settings') ----- - getWebCamResolution - ^ resolution - - ! Item was removed: - ----- Method: WebCamMorph>>increaseCaptureDelay (in category 'accessing') ----- - increaseCaptureDelay - - captureDelayMs := (captureDelayMs + 1) max: 10.! Item was removed: - ----- Method: WebCamMorph>>initialize (in category 'initialization') ----- - initialize - super initialize. - camNum := 1. - camIsOn := false. - showFPS := false. - captureDelayMs := 16. "stepTime" - fps := 60. "guess." - lastDisplayTime := 0. - framesSinceLastDisplay := 0. - useFrameSize := false. - resolution := #medium. - orientation := #natural. - frameExtent := self class resolutionFor: resolution! Item was removed: - ----- Method: WebCamMorph>>initializeDisplayForm (in category 'initialization') ----- - initializeDisplayForm - | cameraExtent formExtent | - - cameraExtent := CameraInterface frameExtent: camNum. - cameraExtent isZero - ifTrue: [formExtent := frameExtent] - ifFalse: [ | camRatio frameRatio | - formExtent := cameraExtent. - camRatio := cameraExtent x / cameraExtent y. - frameRatio := frameExtent x / frameExtent y. - camRatio ~= frameRatio ifTrue: [frameExtent := frameExtent x @ (frameExtent x * camRatio reciprocal)]]. - displayForm := Form extent: formExtent depth: 32. - self extent: frameExtent. - ! Item was removed: - ----- Method: WebCamMorph>>intoWorld: (in category 'initialization') ----- - intoWorld: aWorld - - super intoWorld: aWorld. - camIsOn ifTrue: [self on] - ifFalse:[self off]. - self removeActionsForEvent: #aboutToEnterWorld. - aWorld - when: #aboutToLeaveWorld - send: #outOfWorld: - to: self - with: aWorld.! Item was removed: - ----- Method: WebCamMorph>>knownName (in category 'testing') ----- - knownName - - ^ CameraInterface cameraName: camNum ! Item was removed: - ----- Method: WebCamMorph>>nextFrame (in category 'stepping and presenter') ----- - nextFrame - - | frameCount | - frameCount := CameraInterface getFrameForCamera: camNum into: displayForm bits. - frameCount = 0 ifTrue: [self increaseCaptureDelay]. - frameCount > 2 ifTrue: [self decreaseCaptureDelay]. - framesSinceLastDisplay := framesSinceLastDisplay + frameCount! Item was removed: - ----- Method: WebCamMorph>>off (in category 'accessing') ----- - off - self stopStepping. - camIsOn := false. - "Be careful not to close the camera if any other morphs are using the same camera." - (self class allInstances anySatisfy: [:wcm| wcm cameraNumber = camNum and: [wcm cameraIsOn]]) ifFalse: - [CameraInterface closeCamera: camNum]. - self changed - - "self allInstances select: [:wcm| wcm cameraNumber = 1 and: [wcm cameraIsOn]]"! Item was removed: - ----- Method: WebCamMorph>>on (in category 'accessing') ----- - on - camIsOn ifTrue: [^true]. - (CameraInterface cameraIsOpen: camNum) ifFalse: - [(CameraInterface openCamera: camNum width: frameExtent x height: frameExtent y) ifNil: - [^false]]. - "The plugin/camera subsystem may end up choosing a different width and height. - So use the width and height it has selected; it may not be what was asked for." - self initializeDisplayForm. - CameraInterface waitForCameraStart: camNum. - camIsOn := true. - self startStepping! Item was removed: - ----- Method: WebCamMorph>>outOfWorld: (in category 'initialization') ----- - outOfWorld: aWorld - - super outOfWorld: aWorld. - camIsOn ifTrue: [self off. camIsOn := true]. - aWorld - when: #aboutToEnterWorld - send: #intoWorld: - to: self - with: aWorld.! Item was removed: - ----- Method: WebCamMorph>>setShowFPS: (in category 'e-toy - settings') ----- - setShowFPS: aBoolean - showFPS := aBoolean - ! Item was removed: - ----- Method: WebCamMorph>>setUseFrameSize: (in category 'e-toy - settings') ----- - setUseFrameSize: aBoolean - useFrameSize := aBoolean! Item was removed: - ----- Method: WebCamMorph>>setWebCamIsOn: (in category 'e-toy - settings') ----- - setWebCamIsOn: aBoolean - aBoolean ifTrue: [self on] ifFalse: [self off] - ! Item was removed: - ----- Method: WebCamMorph>>setWebCamOrientation: (in category 'e-toy - settings') ----- - setWebCamOrientation: aSymbol - - ((WebCamOrientation orientations) includes: aSymbol) ifFalse: [^ self]. - orientation := aSymbol. - - - ! Item was removed: - ----- Method: WebCamMorph>>setWebCamResolution: (in category 'e-toy - settings') ----- - setWebCamResolution: aSymbol - | wasOn | - "Failing silently here is awful; but that's what the code did :-(" - (WebCamResolution resolutions includes: aSymbol) ifFalse: [^ self]. - resolution := aSymbol. - - (wasOn := camIsOn) ifTrue: [self off]. - frameExtent := self class resolutionFor: aSymbol. - displayForm ifNotNil: - [displayForm := displayForm scaledToSize: frameExtent]. - self updateDisplay. - wasOn ifTrue: [self on] - ! Item was removed: - ----- Method: WebCamMorph>>showFPSToggleString (in category 'menu') ----- - showFPSToggleString - - ^ (showFPS ifTrue: [''] ifFalse: ['']), 'show fps' translated - - - ! Item was removed: - ----- Method: WebCamMorph>>step (in category 'stepping and presenter') ----- - step - camIsOn ifFalse:[self stopStepping]. - self updateDisplay. - - ! Item was removed: - ----- Method: WebCamMorph>>stepTime (in category 'stepping and presenter') ----- - stepTime - "Answer the desired time between steps in milliseconds" - ^ captureDelayMs - ! Item was removed: - ----- Method: WebCamMorph>>toggleCameraOnOff (in category 'menu') ----- - toggleCameraOnOff - camIsOn - ifTrue:[self off] - ifFalse:[self on]! Item was removed: - ----- Method: WebCamMorph>>toggleShowFPS (in category 'menu') ----- - toggleShowFPS - - showFPS := showFPS not. - ! Item was removed: - ----- Method: WebCamMorph>>toggleUseFrameSize (in category 'menu') ----- - toggleUseFrameSize - - useFrameSize := useFrameSize not. - ! Item was removed: - ----- Method: WebCamMorph>>updateDisplay (in category 'stepping and presenter') ----- - updateDisplay - camIsOn ifTrue:[self nextFrame]. - self updateFPS. - self changed.! Item was removed: - ----- Method: WebCamMorph>>updateFPS (in category 'stepping and presenter') ----- - updateFPS - - | now mSecs | - now := Time millisecondClockValue. - mSecs := now - lastDisplayTime. - (mSecs > 500 or: [mSecs < 0 "clock wrap-around"]) - ifTrue: [ - fps := (framesSinceLastDisplay * 1000) // mSecs. - lastDisplayTime := now. - framesSinceLastDisplay := 0].! Item was removed: - SymbolListType subclass: #WebCamOrientation - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-MorphicExtras-WebCam'! Item was removed: - ----- Method: WebCamOrientation class>>initialize (in category 'as yet unclassified') ----- - initialize - Vocabulary initialize.! Item was removed: - ----- Method: WebCamOrientation class>>orientations (in category 'as yet unclassified') ----- - orientations - ^ #( native natural )! Item was removed: - ----- Method: WebCamOrientation>>initialize (in category 'as yet unclassified') ----- - initialize - super initialize. - self vocabularyName: #WebCamOrientation. - - self symbols: self class orientations.! Item was removed: - ----- Method: WebCamOrientation>>representsAType (in category 'as yet unclassified') ----- - representsAType - ^true! Item was removed: - SymbolListType subclass: #WebCamResolution - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-MorphicExtras-WebCam'! Item was removed: - ----- Method: WebCamResolution class>>initialize (in category 'as yet unclassified') ----- - initialize - Vocabulary initialize.! Item was removed: - ----- Method: WebCamResolution class>>resolutions (in category 'as yet unclassified') ----- - resolutions - ^ #(#'low' #'medium' #'high' #'hd') - ! Item was removed: - ----- Method: WebCamResolution>>initialize (in category 'as yet unclassified') ----- - initialize - super initialize. - self vocabularyName: #WebCamResolution. - - self symbols: self class resolutions - ! Item was removed: - ----- Method: WebCamResolution>>representsAType (in category 'as yet unclassified') ----- - representsAType - ^true! From commits at source.squeak.org Wed Mar 17 14:15:53 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:15:53 0000 Subject: [squeak-dev] The Trunk: Protocols-mt.78.mcz Message-ID: Marcel Taeumel uploaded a new version of Protocols to project The Trunk: http://source.squeak.org/trunk/Protocols-mt.78.mcz ==================== Summary ==================== Name: Protocols-mt.78 Author: mt Time: 17 March 2021, 3:15:53.077151 pm UUID: 5cf20c6e-8aca-734c-9cbb-5513228c669a Ancestors: Protocols-mt.77 Complements EToys-mt.435 =============== Diff against Protocols-mt.77 =============== Item was added: + DataType subclass: #PointType + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Protocols-Type Vocabularies'! + + !PointType commentStamp: 'sw 2/8/2012 17:57' prior: 0! + A value type whose representing Point-valued variables.! Item was added: + ----- Method: PointType>>initialValueForASlotFor: (in category 'initialization') ----- + initialValueForASlotFor: aPlayer + "Answer the value to give initially to a newly created slot of the given type in the given player" + + ^ 0 at 0! Item was added: + ----- Method: PointType>>initialize (in category 'initialization') ----- + initialize + "Initialize the receiver" + + super initialize. + self vocabularyName: #Point! Item was added: + ----- Method: Vocabulary class>>allPhrasesWithContextToTranslate (in category 'translation') ----- + allPhrasesWithContextToTranslate + "Answer quads that encode phrases with (domain) context used for translation." + + | literals | + literals := (self allStandardVocabularies + select: + [:aVocab | aVocab representsAType] + thenCollect: + [:aVocab | aVocab vocabularyName asString ]). + ^ {{Vocabulary class category. Vocabulary class. #typeChoices. literals}}! Item was changed: ----- Method: Vocabulary class>>initialize (in category 'class initialization') ----- initialize "Initialize a few standard vocabularies and place them in the AllVocabularies list. Call this to update all vocabularies." self initializeStandardVocabularies. self embraceAddedTypeVocabularies. + + self allSubclassesDo: [:class | class initialize]. "Vocabulary initialize" ! Item was changed: ----- Method: Vocabulary class>>initializeStandardVocabularies (in category 'class initialization') ----- initializeStandardVocabularies "Initialize a few standard vocabularies and place them in the AllStandardVocabularies list." AllStandardVocabularies := nil. - Smalltalk at: #EToyVocabulary - ifPresent:[:aClass| self addStandardVocabulary: aClass new]. - Smalltalk at: #EToyVectorVocabulary - ifPresent:[:aClass| self addStandardVocabulary: aClass new]. self addStandardVocabulary: self newPublicVocabulary. self addStandardVocabulary: FullVocabulary new. self addStandardVocabulary: self newQuadVocabulary. self addStandardVocabulary: ColorType new. self addStandardVocabulary: BooleanType new. self addStandardVocabulary: GraphicType new. + self addStandardVocabulary: PointType new. + - Smalltalk at: #PlayerType - ifPresent:[:aClass| self addStandardVocabulary: aClass new]. self addStandardVocabulary: SoundType new. self addStandardVocabulary: StringType new. self addStandardVocabulary: MenuType new. self addStandardVocabulary: UnknownType new. - Smalltalk at: #ScriptNameType - ifPresent:[:aClass| self addStandardVocabulary: aClass new]. - Smalltalk at: #PointType - ifPresent:[:aClass| self addStandardVocabulary: aClass new]. self addStandardVocabulary: (SymbolListType new symbols: #(simple raised inset complexFramed complexRaised complexInset complexAltFramed complexAltRaised complexAltInset); vocabularyName: #BorderStyle; yourself). + - self addStandardVocabulary: (SymbolListType new symbols: #(lines arrows arrowheads dots); vocabularyName: #TrailStyle; yourself). self addStandardVocabulary: (SymbolListType new symbols: #(leftToRight rightToLeft topToBottom bottomToTop); vocabularyName: #ListDirection; yourself). self addStandardVocabulary: (SymbolListType new symbols: #(topLeft bottomRight center justified); vocabularyName: #ListCentering; yourself). self addStandardVocabulary: (SymbolListType new symbols: #(#center #topLeft #topRight #bottomLeft #bottomRight #topCenter #leftCenter #rightCenter #bottomCenter ); vocabularyName: #CellPositioning; yourself). self addStandardVocabulary: (SymbolListType new symbols: #(#none #localRect #localSquare #globalRect #globalSquare ); vocabularyName: #CellSpacing; yourself). self addStandardVocabulary: (SymbolListType new symbols: #(buttonDown whilePressed buttonUp); vocabularyName: #ButtonPhase; yourself). - self addStandardVocabulary: (SymbolListType new symbols: #(rotate #'do not rotate' #'flip left right' #'flip up down'); vocabularyName: #RotationStyle; yourself). - self addStandardVocabulary: (SymbolListType new symbols: #(rigid spaceFill shrinkWrap); vocabularyName: #Resizing; yourself). self addStandardVocabulary: self newSystemVocabulary. "A custom vocabulary for Smalltalk -- still under development)" self numberVocabulary. "creates and adds it" "self wonderlandVocabulary." "creates and adds it" self vocabularyForClass: Time. "creates and adds it" - Smalltalk at: #KedamaPatchType ifPresent:[:aClass| - self addStandardVocabulary: (aClass new vocabularyName: #Patch; yourself). - ]. - self addStandardVocabulary: (SymbolListType new symbols: #(wrap stick bouncing); vocabularyName: #EdgeMode; yourself). - self addStandardVocabulary: (SymbolListType new symbols: #(logScale linear color); vocabularyName: #PatchDisplayMode; yourself). - - self addStandardVocabulary: (SymbolListType new symbols: #(#top #'top right' #right #'bottom right' #bottom #'bottom left' #left #'top left' #center ); vocabularyName: #AttachmentEdge; yourself). - Smalltalk at: #CalendarMorph ifPresent: [:aClass | aClass assureDateFormatEstablished]. "Vocabulary initialize"! From commits at source.squeak.org Wed Mar 17 14:16:27 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:16:27 0000 Subject: [squeak-dev] The Trunk: GetText-mt.49.mcz Message-ID: Marcel Taeumel uploaded a new version of GetText to project The Trunk: http://source.squeak.org/trunk/GetText-mt.49.mcz ==================== Summary ==================== Name: GetText-mt.49 Author: mt Time: 17 March 2021, 3:16:27.761151 pm UUID: 3442ef02-57a1-ee45-9448-91ad5a21ce95 Ancestors: GetText-mt.48 Complements EToys-mt.435 =============== Diff against GetText-mt.48 =============== Item was changed: ----- Method: GetTextExporter>>appendVocabularies: (in category 'private') ----- appendVocabularies: domains | literalsForDomain references domainName methodReference | + Vocabulary withAllSubclassesDo: [:vocabularyClass | + (vocabularyClass class includesSelector: #allPhrasesWithContextToTranslate) + ifTrue: [vocabularyClass allPhrasesWithContextToTranslate do: [ :r | - EToyVocabulary allPhrasesWithContextToTranslate do: [ :r | methodReference := (MethodReference class: (r second) selector: (r third)). + domainName := self getTextDomainForPackage: (PackageOrganizer default packageOfMethod: methodReference). - "domainName := self getTextDomainForPackage: (PackageOrganizer default packageOfMethod: methodReference)". - domainName := 'Etoys-Tiles'. literalsForDomain := domains at: domainName ifAbsentPut: [Dictionary new]. r fourth do: [ :literal | references := literalsForDomain at: literal ifAbsentPut: [OrderedCollection new]. + references add: methodReference]]]]. - references add: methodReference. - ]. - ]. ! From commits at source.squeak.org Wed Mar 17 14:17:05 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:17:05 0000 Subject: [squeak-dev] The Trunk: MorphicExtras-mt.286.mcz Message-ID: Marcel Taeumel uploaded a new version of MorphicExtras to project The Trunk: http://source.squeak.org/trunk/MorphicExtras-mt.286.mcz ==================== Summary ==================== Name: MorphicExtras-mt.286 Author: mt Time: 17 March 2021, 3:17:02.529151 pm UUID: 93ba8465-ae64-4145-bf66-6b9918a9b9d5 Ancestors: MorphicExtras-mt.285 Complements EToys-mt.435 =============== Diff against MorphicExtras-mt.285 =============== Item was changed: + SystemOrganization addCategory: #'MorphicExtras-WebCam'! SystemOrganization addCategory: #'MorphicExtras-AdditionalMorphs'! SystemOrganization addCategory: #'MorphicExtras-AdditionalSupport'! SystemOrganization addCategory: #'MorphicExtras-AdditionalWidgets'! SystemOrganization addCategory: #'MorphicExtras-Books'! SystemOrganization addCategory: #'MorphicExtras-Demo'! SystemOrganization addCategory: #'MorphicExtras-EToy-Download'! SystemOrganization addCategory: #'MorphicExtras-Exceptions'! SystemOrganization addCategory: #'MorphicExtras-Flaps'! SystemOrganization addCategory: #'MorphicExtras-GeeMail'! SystemOrganization addCategory: #'MorphicExtras-Leds'! SystemOrganization addCategory: #'MorphicExtras-Navigators'! SystemOrganization addCategory: #'MorphicExtras-Obsolete'! SystemOrganization addCategory: #'MorphicExtras-Palettes'! SystemOrganization addCategory: #'MorphicExtras-PartsBin'! SystemOrganization addCategory: #'MorphicExtras-Postscript Canvases'! SystemOrganization addCategory: #'MorphicExtras-Postscript Filters'! SystemOrganization addCategory: #'MorphicExtras-SoundInterface'! SystemOrganization addCategory: #'MorphicExtras-SqueakPage'! SystemOrganization addCategory: #'MorphicExtras-Support'! SystemOrganization addCategory: #'MorphicExtras-Text Support'! SystemOrganization addCategory: #'MorphicExtras-Undo'! SystemOrganization addCategory: #'MorphicExtras-Widgets'! Item was added: + Object subclass: #CameraInterface + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'MorphicExtras-WebCam'! + + !CameraInterface commentStamp: 'eem 10/16/2020 10:53' prior: 0! + CameraInterface: Simple cross-platform webcam access interface adapted from MIT Scratch. Changes made so that different cameras can be tested when more than one is connected, and so that the interface is simpler and may be interrupt-driven. + + [| form | + form := Form extent: 352 @ 288 depth: 32. + CameraInterface + openCamera: 1 width: form width height: form height; + trySetSemaphoreForCamera: 1. + [Sensor noButtonPressed] whileTrue: + [CameraInterface + waitForNextFrame: 1 timeout: 2000; + getFrameForCamera: 1 into: form bits. + form displayAt: Sensor cursorPoint]] ensure: [CameraInterface closeCamera: 1] + + Copyright (c) 2009 Massachusetts Institute of Technology + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE.! Item was added: + ----- Method: CameraInterface class>>camera:framesDo:while: (in category 'utilities') ----- + camera: cameraNum framesDo: aBlock while: whileBlock + "Evaluate aBlock every time a frame becomes available. Answer a tuple of frames per second and number of 16ms delays per second. + Be destructive; use only one bitmap, overwriting its contents with each successive frame. + It is the sender's responsibility to open and close the camera." + | form bitmap delay start duration frameCount delayCount | + form := Form + extent: (self frameExtent: cameraNum) + depth: 32. + bitmap := form bits. + delay := Delay forMilliseconds: (1000 / 60) asInteger. "60 fps is fast" + start := Time utcMicrosecondClock. + frameCount := delayCount := 0. + [[(self camera: cameraNum getParam: 1) <= 0] whileTrue: + [delay wait. delayCount := delayCount + 1]. + self getFrameForCamera: cameraNum into: bitmap. + frameCount := frameCount + 1. + aBlock value: form. + whileBlock value] whileTrue. + ^{ frameCount * 1.0e6 / (duration := Time utcMicrosecondClock - start). + delayCount * 1.0e6 / duration } + + "| cameraNum | + self openCamera: (cameraNum := 1) width: 640 height: 480. + self waitForCameraStart: cameraNum. + [self camera: cameraNum framesDo: [:bitmap| bitmap display] while: [Sensor noButtonPressed]] ensure: + [self closeCamera: cameraNum]"! Item was added: + ----- Method: CameraInterface class>>camera:getParam: (in category 'camera ops') ----- + camera: cameraNum getParam: paramNum + "Answer the given parameter for the given camera. + param 1 is the frame count, the number of frames grabbed since the last send of getFrameForCamera:into: + param 2 is the size of the bitmap in bytes required for an image" + + + ^nil + ! Item was added: + ----- Method: CameraInterface class>>camera:setSemaphore: (in category 'camera ops') ----- + camera: cameraNum setSemaphore: semaphoreIndex + "Set an external semaphore index through which to signal that a frame is available. + Fail if cameraNum does not reference an open camera, or if the platform does not + support interrupt-driven frame receipt." + + ^self primitiveFailed! Item was added: + ----- Method: CameraInterface class>>cameraDevices (in category 'utilities') ----- + cameraDevices + "CameraInterface cameraDevices" + ^Array streamContents: + [:s| | i | + i := 1. + [(self cameraName: i) + ifNotNil: [:cameraName| s nextPut: cameraName. true] + ifNil: [false]] whileTrue: [i := i + 1]]! Item was added: + ----- Method: CameraInterface class>>cameraGetSemaphore: (in category 'camera ops') ----- + cameraGetSemaphore: cameraNum + "Answer the external semaphore index through which to signal that a frame is available. + Fail if cameraNum has not had a semaphore index set, or is otherwise invalid. + Answer nil on failure for convenience." + + ^nil! Item was added: + ----- Method: CameraInterface class>>cameraIsAvailable (in category 'camera ops') ----- + cameraIsAvailable + "Answer true if at least one camera is available." + + ^(self cameraName: 1) notNil + ! Item was added: + ----- Method: CameraInterface class>>cameraIsOpen: (in category 'camera ops') ----- + cameraIsOpen: cameraNum + "Answer true if the camera is open." + + ^ (self packedFrameExtent: cameraNum) > 0 + ! Item was added: + ----- Method: CameraInterface class>>cameraName: (in category 'camera ops') ----- + cameraName: cameraNum + "Answer the name of the given camera. Answer nil if there is no camera with the given number." + + + ^ nil + ! Item was added: + ----- Method: CameraInterface class>>cameraUID: (in category 'camera ops') ----- + cameraUID: cameraNum + "Answer the unique ID of the given camera. Answer nil if there is no camera with the given number." + + + ^ nil + + "CameraInterface cameraUID: 1"! Item was added: + ----- Method: CameraInterface class>>closeCamera: (in category 'camera ops') ----- + closeCamera: cameraNum + "Close the camera. Do nothing if it was not open. Unregister any associated semaphore." + + (self cameraGetSemaphore: cameraNum) ifNotNil: + [:semaphoreIndex| + Smalltalk unregisterExternalObject: (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: nil)]. + self primitiveCloseCamera: cameraNum! Item was added: + ----- Method: CameraInterface class>>declareCVarsIn: (in category 'translation') ----- + declareCVarsIn: aCCodeGenerator + "self translate" + + super declareCVarsIn: aCCodeGenerator. + aCCodeGenerator cExtras: ' + #include "cameraOps.h" + #include + '.! Item was added: + ----- Method: CameraInterface class>>frameExtent: (in category 'camera ops') ----- + frameExtent: cameraNum + "Answer the frame extent of the currently open camera, or zero if the camera isn't open." + + | packedExtent | + packedExtent := self packedFrameExtent: cameraNum. + ^ (packedExtent bitShift: -16) @ (packedExtent bitAnd: 16rFFFF) ! Item was added: + ----- Method: CameraInterface class>>getFrameForCamera:into: (in category 'camera ops') ----- + getFrameForCamera: cameraNum into: aBitmap + "Copy a camera frame into the given Bitmap. The Bitmap should be a Form of depth 32 that is the same width and height as the current camera frame. Fail if the camera is not open or if the bitmap is not the right size. If successful, answer the number of frames received from the camera since the last call. If this is zero, then there has been no change." + + + ^ 0! Item was added: + ----- Method: CameraInterface class>>interruptDrivenVideoTest: (in category 'test') ----- + interruptDrivenVideoTest: camNum + "A quick test of video input. Displays video on the screen until the mouse is pressed. + Answer nil if the interrupt-driven interface is unavailable." + "self interruptDrivenVideoTest: 1" + "self interruptDrivenVideoTest: 2" + "[self interruptDrivenVideoTest: 2] fork. + self interruptDrivenVideoTest: 1" + + | semaphore height | + height := 16. + 1 to: camNum - 1 do: + [:camIndex| "N.B. the of an unopened camera is 0 at 0" + height := height + (CameraInterface frameExtent: camIndex) y + 16]. + (CameraInterface cameraIsOpen: camNum) ifFalse: + [(CameraInterface openCamera: camNum width: 352 height: 288) ifNil: + [self inform: 'no camera'. + ^nil]]. + semaphore := Semaphore new. + [CameraInterface camera: camNum setSemaphore: (Smalltalk registerExternalObject: semaphore)] + on: Error + do: [:err| + Smalltalk unregisterExternalObject: semaphore. + self inform: 'interrupt-driven camera interface unavailable: ', err messageText. + ^nil]. + [| f n startTime frameCount msecs fps | + [semaphore wait. + "N.B. the frame extent may not be known until the delivery of the first frame. + So we have to delay initialization." + startTime ifNil: + [(self frameExtent: camNum) x = 0 ifTrue: [self inform: 'no camera'. ^nil]. + f := Form extent: (CameraInterface frameExtent: camNum) depth: 32. + frameCount := 0. + startTime := Time millisecondClockValue]. + Sensor anyButtonPressed] whileFalse: + [n := CameraInterface getFrameForCamera: camNum into: f bits. + n > 0 ifTrue: + [frameCount := frameCount + 1. + f displayAt: 16 @ height]]. + msecs := Time millisecondClockValue - startTime. + fps := (frameCount * 1000) // msecs. + ^(CameraInterface cameraName: camNum), ': ', frameCount printString, ' frames at ', fps printString, ' frames/sec'] + ensure: + [CameraInterface closeCamera: camNum. + Smalltalk unregisterExternalObject: semaphore. + Sensor waitNoButton]! Item was added: + ----- Method: CameraInterface class>>openCamera:width:height: (in category 'camera ops') ----- + openCamera: cameraNum width: frameWidth height: frameHeight + "Open the given camera requesting the given frame dimensions. The camera number is usually 1 since you typically have only one camera plugged in. If the camera does not support the exact frame dimensions, an available frame size with width >= the requested width is selected." + + + ^ nil + ! Item was added: + ----- Method: CameraInterface class>>packedFrameExtent: (in category 'camera ops') ----- + packedFrameExtent: cameraNum + "Answer the extent of the currently open camera packed in an integer. The top 16 bits are the width, the low 16 bits are the height. Answer zero if the camera isn't open." + + + ^ 0 + ! Item was added: + ----- Method: CameraInterface class>>primitiveCloseCamera: (in category 'private-primitives') ----- + primitiveCloseCamera: cameraNum + "Close the camera. Do nothing if it was not open except answering nil." + + + ^nil! Item was added: + ----- Method: CameraInterface class>>trySetSemaphoreForCamera: (in category 'utilities') ----- + trySetSemaphoreForCamera: camNum + "Attempt to set a semaphore to be signalled when a frame is available. + Fail silently. Use e.g. waitForCameraStart: or waitForNextFrame: to + access the semaphore if available." + | semaphore | + Smalltalk registerExternalObject: (semaphore := Semaphore new). + [CameraInterface camera: camNum setSemaphore: semaphore] + on: Error + do: [:err| + Smalltalk unregisterExternalObject: semaphore]! Item was added: + ----- Method: CameraInterface class>>videoTest: (in category 'test') ----- + videoTest: camNum + "A quick test of video input. Displays video on the screen until the mouse is pressed." + "self videoTest: 1" + "self videoTest: 2" + + | f n startTime frameCount msecs fps | + (CameraInterface openCamera: camNum width: 320 height: 240) ifNil: [^ self inform: 'no camera']. + self waitForCameraStart: camNum. + (self frameExtent: camNum) x = 0 ifTrue: [^ self inform: 'no camera']. + f := Form extent: (CameraInterface frameExtent: camNum) depth: 32. + frameCount := 0. + startTime := nil. + [Sensor anyButtonPressed] whileFalse: [ + n := CameraInterface getFrameForCamera: camNum into: f bits. + n > 0 ifTrue: [ + startTime ifNil: [startTime := Time millisecondClockValue]. + frameCount := frameCount + 1. + f display]]. + Sensor waitNoButton. + msecs := Time millisecondClockValue - startTime. + CameraInterface closeCamera: camNum. + fps := (frameCount * 1000) // msecs. + ^ frameCount printString, ' frames at ', fps printString, ' frames/sec'! Item was added: + ----- Method: CameraInterface class>>waitForCameraStart: (in category 'utilities') ----- + waitForCameraStart: camNum + "Wait for the camera to get it's first frame (indicated by a non-zero frame extent. Timeout after two seconds." + "self waitForCameraStart: 1" + + | startTime | + (self cameraGetSemaphore: camNum) ifNotNil: + [:semaphoreIndex| + (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: [self error: 'seriously?!!?!!?!!?']) wait. + ^self]. + startTime := Time utcMicrosecondClock. + [(self packedFrameExtent: camNum) > 0 ifTrue: [^ self]. + (Time utcMicrosecondClock - startTime) < 2000000] whileTrue: + [(Delay forMilliseconds: 50) wait]! Item was added: + ----- Method: CameraInterface class>>waitForNextFrame:timeout: (in category 'utilities') ----- + waitForNextFrame: camNum timeout: timeoutms + "Wait for the camera to get it's first frame (indicated by a non-zero frame extent. Timeout after two seconds." + "self waitForNextFrame: 1 timeout: 2000" + + | now timeoutusecs | + (self cameraGetSemaphore: camNum) ifNotNil: + [:semaphoreIndex| + (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: [self error: 'seriously?!!?!!?!!?']) waitTimeoutMSecs: timeoutms. + ^self]. + now := Time utcMicrosecondClock. + timeoutusecs := timeoutms * 1000. + [(self camera: camNum getParam: 1) > 0 ifTrue: [^self]. + (Time utcMicrosecondClock - now) < timeoutusecs] whileTrue: + [(Delay forMilliseconds: 50) wait]! Item was added: + RectangleMorph subclass: #WebCamMorph + instanceVariableNames: 'camNum camIsOn frameExtent displayForm resolution useFrameSize captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps orientation' + classVariableNames: '' + poolDictionaries: '' + category: 'MorphicExtras-WebCam'! + + !WebCamMorph commentStamp: '' prior: 0! + INTRODUCTION + ========= + + WebCamMorph together with CameraPlugin (originally from MIT Scratch) provides an easy and cross platform way to use webcam input in Squeak and Etoys. The first version has been created specifically with Etoys in mind. To view a live feed simply drag a "WebCam" tile from the "WebCam" category in the objects tool. Open up a viewer on the morph and display the "camera settings" category to explore the following basic settings: + + "camera is on": turn the camera on/off. + + "camera number": usually the default of "1" is ok but if you have more than one camera connected then adjust between 1 and 9 for other instances of WebCamMorph. + + "max fps": leave as is for now. It is unusual for webcams to capture at higher than 30fps. See later for further explanation of how fps is controlled. + + "actual fps": read-only. Indicates the actual fps being achieved which can depend significantly on lighting conditions and capture resolution... + + "resolution": webcams can have a range of resolutions but for simplicity three are supported: "low" (160x120), "medium" (320x240) and "high" (640x480). Adjust in good lighting to see if "actual fps" increases. + + "use frame size": the resolution used for capturing can differ from the resolution used for display. If this setting is true then WebCamMorph is resized to match the camera resolution. If false then you are free to resize it however you want (via the "resize" halo button, use shift to preserve aspect ratio) + + + Beyond viewing a live feed WebCamMorph has been designed to support different uses including simple effects, time-lapse photography, stop-motion animation, character recognition, motion detection and more complex processing of every frame for feature detection. The following information is to help you understand how and why WebCamMorph operates so you can adjust it for your particular needs. + + + "FRAMES PER SECOND", LIGHTING & CAMERA RESOLUTION + ================================== + + The maximum possible frame rate depends on many factors, some of which are outside of our control. Frame rates differ between cameras and usually depend significantly on chosen resolution and lighting conditions. To ensure a balance between capturing every available frame and keeping everything else responsive, WebCamMorph dynamically adjusts the delay between capturing one frame and the next (does not apply when in "manual capture" mode, see later). + + WebCams often include automatic compensation for lighting conditions. In low lighting it takes significantly more time for the camera to get a picture than it does in good lighting conditions. For example 30fps may be possible with good lighting compared to 7fps in low lighting. So for best capture rates ensure you have good lighting!! + + Cameras have a "native" resolution at which frame rates are usually better than for other resolutions. Note though that the native resolution might be *higher* + than the *minimum* resolution available. It pays to experiment with different resolutions to find which one results in the highest frame rate. Use good lighting conditions when experimenting with resolutions. + + + "MANUAL CAPTURE" MODE + =============== + + In simply usage WebCamMorph automatically captures a frame and displays it. To support Etoys scripting a "manual capture" mode is provided where you or your script determines when to capture, when to apply effects (or not) and when to update the display. In between these steps you can do anything you want. Note that frames rates will be lower than that in automatic capture mode and that "skip frames" (described next) will need adjusting at very low capture rates. + + Tip: In manual mode the camera can be turned off. It will be turned on automatically when required and return to it's previous state after a frame has been captured. For capture periods of five seconds or more turning the camera off may save power, which can especially useful when running off batteries. For smaller periods leaving the camera on will avoid some delays and could help speed up webcam related scripts. + + + "SKIP FRAMES" + ======== + + Webcams and their drivers are typically designed for streaming live video and use internal buffering to help speed things up. At low capture rates the picture can appear to lag real-time because what you see is the next available buffer not the *latest* buffer. So for example if you capture a frame every ten seconds and there are three buffers being used then what you actually see may be thirty seconds old. We have little/no control over the number of buffers used and the actual number can vary between cameras and under different circumstances for the same camera. "skip frames" is provided to compensate for buffering so increase it when doing "manual" capturing until you see what you expect to see. Typically a setting of 8 is enough but I have had to use 20 with one particular camera in low lighting. + + + "SNAPSHOTS" + ======== + + Where as "capturing" is the process of getting an image from the Camera into Squeak/Etoys, a "snapshot" preserves whatever is currently displayed (which may be the captured image after effects have been applied). To store snapshots you need to designate a "holder" which at the moment can be either a "holder" morph or a "movie" morph. Create one of these before proceeding. To assign a holder open up a viewer for WebCamMorph, display the "snapshot" category and click in the box at the right of the entry called "snapshot holder". The cursor will now resemble a cross-hair and can be clicked on the target holder/movie morph. To take a single snapshot at any time click (!!) on the left of "take snapshot". In auto-capture mode WebCamMorph can also be set to take multiple consecutive snapshots . First, before turning the camera on, set a sensible limit using "snapshot limit" (to avoid using all the computers memory) then set "auto snapshot" to true. When the camera is next turned on then s napshots are taken for every frame until "snapshot limit" becomes zero. "snapshot limit" is automatically decremented but not reset to avoid problems (although you are free to reset it manually or via a script). + + + "EFFECTS" - WIP + ========= + + Similar to snapshots, a holder can be designated as the "effects holder". This holder is intended to be populated with "fx" morphs (coming soon) which will operate on captured frames prior to displaying. Stay tuned ;-) + + + CLEARING SNAPSHOT & EFFECTS HOLDERS + ========================= + + Keeping a link to snapshot or effects holders can tie up resources even after the target holders have been deleted and are no longer visible. To ensure this does not happen designate the WebCamMorph itself as the holder (for method see "snapshots" section above). + + + COMING SOON!! + ========= + + - Built-in basic effects such as brightness, contrast and hue. + - Image "fx" morphs for effects such as those found in MIT Scratch and many other types of effects/ image processing. + - More snapshot options, eg, store to file + - Demo projects + + ! Item was added: + ----- Method: WebCamMorph class>>additionsToViewerCategories (in category 'scripting') ----- + additionsToViewerCategories + "Answer a list of ( ) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories." + ^ #( + + (#'camera' ( + (slot resolution '160x120, 320x240, 640x480 or 1280x960' + WebCamResolution readWrite Player getWebCamResolution Player setWebCamResolution:) + (slot orientation 'Natural (mirrored) or navtive (as from the camera' + WebCamOrientation readWrite Player getWebCamOrientation Player setWebCamOrientation:) + (slot cameraIsOn 'Whether the camera is on/off' Boolean readWrite Player getWebCamIsOn Player setWebCamIsOn:) + (slot useFrameSize 'Resize the player to match the camera''s frame size' + Boolean readWrite Player getUseFrameSize Player setUseFrameSize:) + (slot lastFrame 'A player with the last frame' Player readOnly Player getLastFrame unused unused) + (slot showFPS 'Whether to show the samera''s frames per second' Boolean readWrite Player getShowFPS Player setShowFPS:) + )) + ) + ! Item was added: + ----- Method: WebCamMorph class>>allOff (in category 'accessing') ----- + allOff + self allInstancesDo: [:each | each off].! Item was added: + ----- Method: WebCamMorph class>>descriptionForPartsBin (in category 'parts bin') ----- + descriptionForPartsBin + ^ self + partName: 'Camera' translatedNoop + categories: {'Multimedia' translatedNoop} + documentation: 'Web camera player.' translatedNoop + sampleImageForm: self icon! Item was added: + ----- Method: WebCamMorph class>>icon (in category 'parts bin') ----- + icon + "Original file: imagecodericon.png" + + ^ (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: + 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wIECy0ZfllfzgAAAB10RVh0Q29tbWVudABD + cmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAgAElEQVR42uW7yZNsV37f9znDnTOzMrOGrPHh + oR7mBtAC0BPAbpJqEpQ4tNkSF3JYbdMOLWhHmOEI/wE2rFCEubFX3lgOO+wQg3bYEbQtyaRE + kGx2mw12kw00UOjG9F7VG+rVkDXkeO/NO57jxc33RMlaOGjvfHKRmXc4957fPHyP+Dv/zj/E + sdhagBYGi4MUFolFIkCCxGIRSAwIiUCCAOzynBCAQNm6uUtUWCTWSoTNUEgqdHOLfTRbCbam + RpFkKZ6nUQgMCmyJNGCExVpBbS3SGmorELYGSoy1CGupLUhbUloJFszyY2uohUEYS2UBarCG + wkgsIGyFsUZojbRGShQgmvUiEGhoFokAFFIYpBXUQiKxCGGQFuzyv0GBUGByhHARGIwpSIuS + dtBCGwXUGCqsUFgcjHBRtsZBUywKoqCFFBZhFIYKZfVjwhs0ippHbyix1ABIauEgLECFxCBs + hRVgLYBFixprGiao5VVWgMVYDQ6KZvUKg6DhKlIgl48DgUWjhEFhG7pYgRUSjcBikLJGGkuF + beZDkBUZ8eyalhdRlTEC0I7PxeiM3kqPoqxx3YiqzkizGLCsBC0qKaA0CCkBBcKiqBsiYxHW + wYoKg2iOGIm1AgtYKkrhNdIpDJYKYxWCumGlsAhbUyGRgNYIpBAI7HKxEiXA0nBWCttw2QqU + kA0XhUJhANlQXgiEtRgMZVkjVEpRg60LlK2Zzy6oqoLuyiZlWTKbXSAxeG5IWlRkWYanFZ52 + QGjmkzOEgDDwwBYIYRHSRS7F3oqaGom2GqippMDaRn0NEtcajKgwVoBt2AHgILBU1Ev1NVai + lZCNbi8pIgQIIUFKpAGExcFihGhURAgU9rFcIFhyxzJLZmBKLscz8ioj8kOqyuBqn9n0iqLI + KaqS4fkdiixlc+MGV+NzHOkQ2xzX8UC7aKk4v3zIk0+sEsdX+F6EK10QAiNV857WYoWlRqNZ + ijxgoBF1C5ICKy1YSy0bRRXmEbMVyAopRSOyWliUACUaCXCsQUvQAqQERxq0MEghkEiUkIgq + BVNhASksgeuySFMUFbYqUNLB1CUtP2Rz7QlG4zPydIKQBmtKTs8Pub6+x2h6CqYkTWY8PDsE + BHsbW8wn51RFxWg8BGq0AFdWCCGRj5gkDA4GJcWSORIXs7zGQ+IihUQh0VaiUDi2+a2RaEmz + wEb3xVIJQEiLwGIBhcCKxjgKDGU5o6wsk+k5SrlEviYMutR5ChhGk3MCNyJfzFGipqoLfM9F + K5duu890dkGezVnkCVWdM48nbHQ3efDwIzqtNYoiazyBkCRZwqC3g5Ye2haUVi91W6JsI4VW + iMbjCNNwG3AaX4BFIIBqadCNhUq4SFsBoJVkabQatydFI9ZFkVOWC9phCyldhGgmSpIpR/d/ + TLc7IJ5PUMphNitZ6WR4TkgcT5jPr1Adje8HXIwvaUc9JtNrdtc2OXr4Ma52OLs+pt/qc3Jx + j+2NZ5inY3ylqcuUdDFllgwpixypFIPVHYQtQEhcaowFI0xjjqWiQqKoHou6tBZhDLUQGGPB + SrQwGKuQ1CBKrBBIC+r1V/7WW1I0oi6URC5FvioWXF+fEkVtfO0iqUmTGXmRcXZ+iKM1ZTFD + Cpd7Jx8RxxMc7aNsjudFFEXCfD7m+PxjrmdD+p0+dW1oeS1m8ZjpfIhUCoVlkceMp+dEUZu8 + WOC7HvFihrRwNTppRFsI+lEPgUQLixCWLJsihcB9ZL8AtZQOxCNpNs0ZIUGYxk3SSDcIpFrq + vhCicXNLmxAGEZiS+fgSCSySGKqClh/R66wSuS5aaabTM4TJOb28w+XoHoEX0o1Wmc0uOR5+ + ylp3hyydoRHMZ1dIoBVEtPw2UNHvDMiLFN8NKPI5eRajpaTltijrnCjoMJmeU1YFQoBDSVXO + mUwvWSySJiCSoKRFSIEUEkfUuFhcajTNurS1zW/AEQIlNFqAVkIg5FL/xTIAMjVxnhLogNB3 + GY/PqKuKukjprQ7otlYpyhRfubitLteTh7hSMb4+pi4yJAYpNRu9deqqwpic0+EhWvkoDKEO + cLXDZD5kc3eT46EhcgKm8zFrK1ucX92jHXYwVY7jKOrasN3fwFeSqqwYja65ml3Q767SUgKE + xRqDEBprLYgm0JG4CFmBlVgJ1jTnKmwTqFGjvvbq336rsf6NLZBCohRUZUEcT4njMdPpBVJY + LkZnFMWCPI1RWjKaXBEEAZur27ScFq52UBLKfMFad51FNsXVDtP4ErC4Ggb9XXbW9ji/uk8Y + tJjGUwLPxwiLVopeq8/V5JQsT3Edj+l8RDvq4iqP0PNBaLI8JcnGVKZmFk+IXI1GNMZcNqG6 + xiKpEcJipUSbZQBHoz5N0G2QjftrQkstLBqLIwT9Voubm0+glWTQ26KuYm5t3+L0/A5Iw/X4 + go3uCot0xjwZE0ZtQrdFWS6acKPKGaxs4igXR2usKZknU1yt6LU6+MrHc1xGsyGzZEw36NBy + QtLFGK01Hb/DbD5id32fyA3whebq4kETUdqSoki4uLjPeHrG8dk9FsUCIQRagCMMUoKWAo3C + txWOBEc1a9NC4gqJQqMf6bxYuj8pl+GwkHQin5dvvcTl+JyyiLi4PmGwukm3tUKxmHNycY/9 + radJ85ittU2uhGCWXFDZnNOruzjKxdoaRzi42seRikF7jXQxYX11lSxbgKjZXbtBVWTUpiZO + p4RuSOD5VKagKjMQhrPRPbZWb1DnKWk6pswykmxCKwg4vbyP6wZsSkEr6oK0YAwGqJXFGNV4 + CCtQyqCsxViJEjXq577wzbe0AC1ByiajE0qghQVrsKZGAaVJKRcJiyKl47fxPAdpJdZWTJMR + ZZUx6G7iSoWQNU8NnsbXktpWlFXOjY09snyBi0ucXbO3sc3xxSGB26LthjjaoaJiHDeGshNG + zBdzZukEsIRuQD9skS1S0sWMvExJypg4S1jr9HGlizA1i0WMIw2OUkglcaARdcEylwEl6ia5 + w6K1oElwpEAIQ5WVuNJBWnjw8Ihuq8UiqxClYLXXo7zKuJpc0otcZsmUss4xdUboubQ9h0R7 + YAxX8yGBdmnrkGF5wmR6xXwx4Xh0xLO7+yTzKXEWo7XDRmeNoig4m5wyjScEXR9hJL7jYUzN + Wtgjy2fcPvmUyIsYxZdcxRM810FYhWmvkmdj3nv4Y3Y3bjC8hhf3X6ItQyoJ5lGwbgRI0YTK + dY1RNdp55AaXkWBexDw4HSKVRBrLw7MjdreepBV1uJ6coZSlH4RM4xFrgU9mHKZpSpbOGE8u + GHR7dALNdz7+HqtRj7ossLZif3WX3zv9iEWR4GDwgogb3W3uX58QxxPSKqMfdHhgDD2/TWUW + hL6HwLDie8xyQ1UVTOMFpoa0mBP5GyihMLYmSSbE+RhP3aQoFtRZiuOHaAtG1djaUisLpqkv + NFohUb/05V99S0lw1NJ4CIGUEqEsrdAn9AMm41M67ZB2GOIKwyyZ8tz2La6nF4znVyyyBEdK + 7p7fIXAUW911bnQ3OZ2c4TmKk9GQMAjJ8pzQcYlCn4fXD6nKglf3X8BFIxQ8GD3kmc2bICX3 + Lx6w0V5lu7+FsSVX0wvWW32m2RSLYbyYUpmKylTUVcE4HSMEJIuUtVaH0A1YaXVwl7GBlGJp + 5E2j6tgmzf43vvyrbzlS4GDR0uC7DqHjoAV0oxDqgpVul8n1OdViQTsIuD+8hyfBmgrX0fSi + DmkxZ5RM6YdtIsej31vhfHyKL33W2n1Oxhf0/BYPRycE2iHwAna66+xF69xYWyMUko+Gd+j4 + LR5cnvDKzeeR1nJ69ZBaQNePaLsBtiq5jK9pBSFaCF4Y3OIyGYGtWQm7hK5GW4GWkp3+Gq5W + aGnRsEyYmqhXLb+1Lw1SNimxpMn4XMdyfO8+4eYWg3aIp10iUzNfzEizhLxaEAU+T63uMk5G + 3B7eZ6Pdp+9HjJMRq60VeoXHemeFjtNivb1K9dmfc+fihMDxuHP5gBsrm8x1yMyb4juSOxf3 + qA0MZ5e4jiKvcrbaHS6mV3R8j74KyaqCnU6fu/MLpDVsdda4Tsa0HYdZluJhqIuctf42HjUu + NZ5svJsVYKyhXn5bYzGA+jtv/MpbjgRXGHwloS5ZJDMklvfvfEjkeswmlyghCTXcXN/k5d1b + /MmP32E+n7HZ7fP01i5SSm50VzHS8uLOPi3fI88WzNMFz6xu8PDyIVVR4TseJ7MRT3f7CCu5 + udKjqzU/vrjLVTzm5uoAW5aMkxkv7OwDhtDxeGp1i6LKmeUJJSWOdhhEK0SeR1HmFGXBatjG + mhpBzVee/jwtz4UyRguL6zRBmjIlWoMSjUqov/tT33jLV+Zf6IetKRYJVZYQKknX83CEoCxm + FGXJs9vbpEnMiutzdPWQqlpwdHaPQMD+1ja9MGJRxmxGbZJswV/c+YDQwuX0kid7A6yjuH35 + EMf1eXF9k9PJJVIKPro85rUbt1j12/zk7AghLWWWk9cFz/c2uTc+Z80NOLi4h9IKH8l1Nqcy + FdbUbLV6SGNouQ6rXoteELLiOSySmLJc0I0CsmTGLJ2xEgS4SqCUQEYSAqlwTEWVJbi2YHOl + jY/BGENRpjx3Y4/nt3fZ6XW4fe8Tyjpj0O7wpZv7nCcjWqGHq2CaTLkaDbl9/zYulhutDl/b + f44fDY/Qrssbt55jMR+x3e7ytSee4cfDB0Seyx/eeZ8vbN1AmMY/f2H7JoF06XkO2tZ8NryP + omIaTxFSEiI5T8b0XZdt6fLKxi55lZKbjMBx0LagymNG1+fE8TWT6TVUOapaEIkaX1kCDYEG + 9fd+plGB0NFoBXmaoJXA8TTClrQciawrrq6HPDHYZDqf4inBPJ3yzGCTLoLj8SVP9weIPOWJ + tQ3SPOeT40Oe7/fZ669wGU+Y5SkPL05JTMXh9ZCNbpcimfPj61Ne2drjfHxFUqUUZYWUlo52 + OYvnKCFouS7D+ZhZPqfn+Pzo8pgv7ezzQm/AzY0BabYgr0u2W108a/jcYJet9grHlw8RdU1c + ZWyELe6e3acXBgy6XbS0uBh0IC1aCKS0hI7LeriBsDVJbNlducU7H/wAbS2yLkimV/SUxKfG + 1YrT4we0sfybL73Gf//n32a6WPDqzpP0gpDzMiVPZuSzmj6aOZINz8cYQ1WVzGZTtjsrSMfh + 8701/qvDj9jo9XhxtcNuq829yYSXNrf4zuEnfFLl/PTuk1RVzZ+ePWA9iHClpRt6mKLk0+tT + nt/YJjCCjIKr2Yjjy4coxyFyHZ7qrfHg9AGDlR47a2sECmorqaVF/eZf/5W3PAmuErhS4Uvw + lKIqM7J4xvZKl1k845PTQ165cZNeOyLwAgKt6IYO4yRhOLrki3s3+OnnX+Sz82NO59f88N4R + n9vd4SvPPo2rNR+f3OfW2jpPr65xd3LJ5/sbfDYe8eLaGnVdMC1yvvHs8+y1Wvzw5Jjb4wu0 + gJ+78SQHF2eUxuC6DkVV8sbeTb564wk6QYt37n3KRhCx3+5ye3jKMJ1xEU+Y5QtCz2Oj28VW + OcpzeWFnB1drAtfBlRIpQf1HX/uFtxwl8ZXCU01AJIWlLhLmoyHnl+coUzOfTbl9ecbmSpfp + 9Tmj6RSpFVW+oBv6XM8mrGjJ87t7PLO2xsu7N/jdd7/P1mCbvEp5dvcG/+zDD3hqpcP3Tx9C + bZBaMZqO2dre4u//4q/w/mef8s/uHvELzz7Hz27v8cnogn9+7w43+j3+3dff4KX1DT69uGS7 + 1eZ0MuEnl6fMFgl7q6t8/eln2Ah8Pru+xHEUu2FIoAS7vT5Swl67Rb/TphOFBK5EKnAVaGVL + AsdFK4FUIKyhKjI8JfA9D6UNx1dDtgZrlEXGj48PeWZjg/l0xGV8Teh6jPI5/cCnMiU7qxGz + i4wnb+5y93SP3/vB9/hbr77Ca6++TJol3L+8pipKBqs+f3B8j19+8XP86v5T/N4Pf8A/PbyN + pzWfXg55dn2Nw9E1rz9xky9tbfHkxgb/+T/5xwzTmM3EY73b5c39Z3my3eLo4Ql/cPAeZ2nM + zVbE3SSmF0T0eisM+h12+32kqbHSUlcLWuFK0zuwoP79L3z5rVbooaRFO5IyHiFEjSlTtK1I + rye0PU0r8FgUJZ4j+f6dO2z3O0SeQxLH+FJSiBrlOMRxyuDpJ5CO4tUndvj9d3/E3/u3/jbJ + xTnrQvPe4R2MqQlaEWeTGYFyOE+mnM1TfutXf5kbvsu//dUvcTGf8+3PPuM/+eVfpCgL/ss/ + /iO+/sxT/Gd/829w//QMV0rKquDe+Tl3x2NOkjkvDdb5yv6TTEZXjBcJL+1ss+EqFumUzY0N + gkDT66+hXYHWEqUE6j/8wlfeWumvUGYpxmTMry6RWiERJNMxg0GfVhRSmop2d4W6KMjqnLwo + +NzNGzy1O+Dh1TXrg1XC0EeYgifX+6Aknz084fbJGT/1wrOY6yu07zFJY/74s7ucxTF//xf/ + BhUG8oJfe+VFHM/Bk4L/6d0D/ocf/Dk73S4nSco/evcvuNHtcj6f8979Y3ZXe7xxc4+B5zZN + O9flZ3c2KfMCKwWfXV7wTK9HMZ/w6fU1G0HA9fiaTuDhtyKUo5tkTwh0kU6g6BK1Q9I0JS0X + jE8mtFsReRFT2YoHp+d4gcdaN2LF6fDMzio/vH2XP//4U9aDgBtrK5TADz7+lJYfcng15rUn + d/nw6IhxuuDO0T32dzfo9Xr82s0d3r13zIM0A1ey1vJ589WXKX2HoL/Kx6Mr3v7kY0ZpwtO7 + 28yTOa+srvGzN3dZdTx29rYZXU84vb5m0G5xOZnw2pM3qdOMpzZX+fjskrVWxI/PzqiswdUe + sip549lnubwaobQGDK31Laraon7zi6+91e608FoBbhjgCKjqisl4Qif0CLtt1ntdopYPdU2J + ZTKPafkeoqrITcXO0/tMT4eUdcVsseCFZ27x4Z0jji+uEVh2Vnvo8ZTJyTntXofRdMp3Pzsi + Kwt+81e+Tr/fZn2wxvuf3uEff+8HLGrDRiviP/jGm1STKT+/u0XUDrl/fsHh6TllVXIj8HFt + zXlWshr4UJU8WOTcubzk2dU+z20OeGV3h0CARuL7EXlZ4GgXN2wvgzyDuPsn37Z5nqN9nwfH + x+xsbyKtxXMkWZEjtQLThMpCK6SgqbzamlmaEgUeVVlRFjlKSqJWwOX1CF9LxklCWpTsddso + a/B9F6kl5+MJV7OY9W6b7V6bui4ZzRPSPEMYw1WSMOi0kEKQ5hlVWRK5DspUuFqRlSWVtSRl + Tktpeq2IcZoQuJosy/BdtymJmWpZ3hN4rosBsBbXdXEcF2tBHz94wOdffomo2+bJm7sIAWW2 + aNqnwmLrkqoouLy6Ip7M8H2XwdaARRyjpc/qWp+6KqmKHGkNaMlKa8DZ5RVd6eMWAu3CE1sb + FHlT98syQVZLViOBFgWXsxGdwKUXeJxOJnQCCH1LVizY7bq0XZ/ZYsFlkrGoa0JXgTU82fEp + 64pFOcLVNZHnIykItaE2FfmScIuyQKLpBiEI8FyFVAV1VaHBYkzNu+++S3dlhfXVHmEY8tY/ + +C22tgb8tZc/xxuvf4GTHw/5H//n/41v/uLX+d6f/QV7N3c5v7hisNrl4KNP+dnXX2U6nZEl + Czr9DkmacvjghNB3iWdz9rc3iOcxYeTzv/z+n/Lrv/5LnE9jAlfzxMYaaZ4xTRKUUpRFTrxY + 0PFcitpwnZcsipJ+EFJh6Houi7JgukhZ8T08J2SyWJCVBd0oIitzlNSEWqKFZEVJpNQIAVo1 + UlzXNcYYZJomGFvRikLe/pPv4gYBytU8/exTfPWrX6asa6q64ktffIWbT+wQrbTxIp/LqxF3 + 795neD1io7/C//5P/4hPPj3kejzmu9//ET/zlc8zPLvk8y/c4qPb9/mLH31CVlZo3+OnvvgC + jtb02i1ubW9wMZkxmsckWYYFXtgasN9bYdCO2F3rE2rNahBQY+mFIcYYLBB6LnldM8sWrLci + Wq7LoshwpaLjB3Q9n07gEfk+SjbNXakUlqYHIaRA/cf/3q+/tbbWw0rJl7/8GlorHEexSFMW + acr+jV3agUddl0gpuXnzBhtrfTrtiHY7Yv+JHXY31xhs9Ol0WziOw4vP3OTw8D4vPHuTXq9D + aQzHD4c8c2uP1197gbt3T+ivd1jkOXGS0vYc2lHIJE3Z73eJfJd4sSApcsqixNqaeZFTVBVt + V4MUXMYx7TCgHfj4jmYlDKiqiq7vo6wBa6hN/ZcAHCClXC5cYu0SC/HhP/lde+vWTfxWhDX1 + EvxksHUFtqaqmmOysSZISVN0WJaXbFVRJHPm8xgd+AS+y/jqCkeC0ppFXXE9mTa1wrUeVZkz + iWNOxhNWo4Ab612yLOOT0yGb7ZC8KnEd1WABlCB0HbSEO+cXrPkuQgrujkf0WhGOtRhqAsfB + kZBmGSuei6kqLAZHK7R2KIoCpVRTG9R62QURGGvR/W6L8Xvv4yGa/pqWWGMpFylCaTA1Siuk + 1gjHBSmwVckjElpjqPMMqTWzJOU0TkEI1td6lFlGnC44vxrTW2njrMRgDUcn51RAq9vh4qTi + 9oMTirqm8Ga4UhK5DmEUMs8LYldTFSXX44REZ1xnOW3PRXYUqbGs+i2UVtRVgVM7pFJSVzVa + K0ohQQry3MEYg+f7LLtj1KbBIOmyLHHjmM7Xf4FFVdJe6WCMbRYJfOePvs3+E/tsbG42RFCS + ujZYY1BKI7VECEEynxNWBl3VJFnOWVmhlcJ3NDtVRW2hN1glSVM64xlGSNpRwEWc0H7qFVqu + y8ZaH08IbF3iOy61kJRlSVlXOGnGPMt51lHUpWFcFjyztornuiilAcizHD+MKPIM7biNC6fB + CFjbgD2ssVR1TVUvCSCUoKxqvv0nf8w0nrO5vc0iy/GkYDadYeqaq8tLHjx8wMXVFSiFpzV7 + T93ic8+/QJkXoBVhFGLKgjwriQIPIQRpVXI+mtHrtLgYTZglKZHrIIWkrA2TRcaiqhi0I57Y + HuAFAaYoKXJFssjwPJeqKBsbMhqz1elQGktqDXsrK+Rlhev5y+gOpCwxdXMMAaY2CKmQUmBs + I63GGqRSOFJSVBV6Po/x8gXCD7ixs4Mb+rRaIY72WOn2uB5dsbm7RZwmdFb7tPpdHh7eBWNQ + CoQjsXWFMVDUBuW5OJ6LsDW6VqystLm6HFEZuJwn9HcHDbBKS3zXwdGK7dUeZVmxKOdUWYFW + EiUleVZwnSRcpCmR55NXNZvtNnFeUCOpMWRFzTydoZVGKU26KHHdprdpRINis8ZQW6itpaoF + VV1SLYmhq6riahrzxBffwFeKKPAxSiEsOAKevHmToNViSwrKLEdKxc3BTiNauaEqDVjIyqZH + oLWmSHPKosJzNY4UbPZXuY4XVLVhOI6XZXgoqhpTG4bXMxyl8B0X13EbqBeSOE8ZxinacegG + bSxwleaU1uDTJGzzIsEYQ+QFRJ7G8wOWEDbk0kYVRYF2HIQQOAr0UmWsBf1wkWEqwyqayzTD + y0o8R9MLQgoEH3/0E2azOVVtKKqKPFvwpVdfYzIZY61FSEUQhkghWFlZ4eDDA37qq1/j9//5 + H/L8s88xmU5IFwsmZc725hZFXXNxecGDkxOkkOwGEXs3nyCZTHj1lVf44OBDur0eH9++jbfa + 42R4zlbUQWxtMVhfp7SN/i7qBZ0gwpUKJSRxvqC0NaGp8bSDBVwJxixtvrV4SmAt1BZMg5dF + a6lYYJkWBTWQW9BWMi9qlICtW89w50//lMpUUFSs9Ve5fe+YLFsgpWx6/9cjTG0bXasb8jva + ZWtnl08+u8Pp2RmjdMbO9i6udrj38CEgmE0mrODw3f/zzyiLgvbagKtZQlzUHJ2fEx/fJ5vO + eebNN4lWVpjlOQLIyoLAcZFYyqrCSE0nCClrS2klSZriCIkUFq29JivEUFXmMRZOLKve4n/9 + 7X9o+eiI9Z/7BSQCrSQdLyArS1wl8bSmrg3dMEAKiVCK4fmQ8/MzvvSlLyHlEolpDVVdN8Aj + CaZuYoisLImLnEVZkhQFSghmRQ7AXrdH6HhorRvElta8//77rN+8QVzk9MM273/wAa3eCv3V + VWpTN2BJa9BKsxqtYI2hrMsl0R0C18cs8ctK6UYNrG3C3iWWsDI1RVlijEHXtsZdtouU1Kz5 + AVYIjJQNGtPU+FpjTMV3v/cOe3s32NveYmvjc7jSgqgacZICXwqKoqBaVE3kZCyhI5FGoa1h + ktX4vo8pMlbDkLUwQEmFkIraNNCVzu4WRV3S9X1sXbD/zC0AKtOgUR2h8LXGkZo4Swi0S2UM + jpTLdFcv0V8NMFYs8YFSSYy1lGXJosgwxlAvwaDYJexcW8PVIiWvKzyliRyX3/0/fo+vvPYq + 3V6f89GIMGoxPD9ndH2N42harYj1tXWef/55iqLA2mWvUWgq08DVXdfFYAm0ZpQmj2wUtTEs + irxBsVk4mc1YVBXPrK9j6pq0KOl7Lq6UXGWLpqdnK6yRRFqTVzXalmRVQcsPQEBIRWFqIlfi + Ok3sX1uLEA2WNsOgK0NhDY6j0MbWRFriqwYd7iiBtJKOEnRDzTd/+ivs7e02Fnxvk1tP7ZEt + FqSbPTprfS7OhwQtj9Zqq8Hgul4TZRnTqEZdUZYF0jisSsv0IkMAviPx1jqsaAVlxe0Hp2gp + eHFvq0mrS8PG+jpFmlGVBWDISsmkKPGFQNgSJSw9T9F2gybLsxZjKwIt8bVAaoHWAqFUgyY3 + NdJqFJpFUS5dtTFoLIomtl9zHXIpaAdNMLG2tspkOicMfV7/6a/iei4Yi1ASW9fs33oaUxWN + blY1dZYhZPM7Sxe4WuF2WmgktrbcvbjGAiudDqHrUuU5RydDamO4ubGGpxykViRlTLooyRY5 + YHEch2lWLHGBkmzZ3Z1VjTGTxuA7DTrFEQ5pZZq2uARbW4w1VFVFVVoqoyiARZmhBYZJUeIY + gy8l10WFtRDHGZVpABO+1tGZ8eYAAAbgSURBVMzjAjPLMECoHW7fuYOjNZPr6yb2X1+jqCqu + r6546ulnOD09pb+2ysbGBu/+/rfptNtkZUG0t8v58QkP3vsRX/nq1zgbXXH/3gPGDx/yd7/1 + LeqqRioorUMyy9COxySeUZia0sLCGKqySdAqYxjlJUKIRmVdhe/5TNIcRzuoomn1C9HsEjHG + YEzd7EKhIaI0WApjyOqaaVlytVhwnWWM85zaNgjSvK6pjaUyFmMsxlo+/PCAs7MzhsMhvu9x + cHBAPJ1SLjJOj+/TbYf0WxGB67BIYyZpzMnlJQb49PanxLM5cVkghGQzCtkcrHPy4AG+q/G0 + xnc0vqsQpqLlNnbAk4KW08BmXNE0c5QQBErTcX0cYfGExZMQOgppKqSpcKXBkxZfWlwBylY4 + GLp+iPid/+6/sHxyTP/rf7MxTkKgxRInbgUtrREW+oGPsGCW+zIixwVriTxvubXG4rkuOvCR + vtdkklJQpilSSoypSWZzfvjwjMViQbVYsLW5yV+7eQPXbbI1qdRjY1XnJcl0gnJcsmxBXtVU + xjDLC4SSZFVF6DhkZUVLO3iObup+xuB7AWVVopTCcRzkMv9/JAWLvEBIQV3XTUnsLw+7hJsr + IaisYVY2+p0njR+tTI1EEOqSw6O7vP7Sy5hluLW4GjMajXj66adxXRetFe9/cEBVG6bTCc+/ + 9CIW8IKAXrvNjfYK8XhOEIbNxiubo5RuKrZFQVIY4vmEyjZSV5oaiyDOcjypyGuDkRKrJHlt + mcUp3SiiqOtH2HfK2kK9DAeXqbDWmrTIqGuDbgLvf5kIxjbp4yNuAJTWYOrmuBKC77/3Hu8f + HPDZe++xt7PN1tYmF1dXhK7DYpGwe2OP7Z0dtnY3uXP7DtrV+IGLnTfz3equIE2NBJQjm6xS + SrQW2ArSMifJF6RlU4lSS53Xstl1JptUH0cIPCVZFBVCWAJH4zoO4hEm3Db+nqU6W5pKkS8V + Vmn0v7L2fyEJS2l49Mc+2jwhJaUxdNbXef6lFxEIfnh0xOt7e6jBFscXQ04ur5kol0xojk5P + SGYxo+mEaGfn8fzDJCEpSlwhsOMxxlgKa3GlXD67IbojBFVVUizVTwtJx9NYA5EjKYylqgrm + RUHXb7CL3TBAa73cySKwtsZY0ewiUQ1RkjIHaxG/89/+luXTU/pf/yX+3wzx+Hv5EY9oZ5fb + 1xrq/+vo/WinShwntFutJakFzS7A//tQy80bj6RVy2YniK8kEkFtDUpIXCXJ6gb6G7oaY6C2 + BldKKmNIKkNDyr/CePvtt7l16xaHh4fcutWEq8PhkMFgwObGJod3Dx+rz/BiyP7+PlEUMRwO + ARgMBgwGA95++20ODg548803GQwGHB4dEicxSZxgsQyHQ15++fOAJY5jXn75ZY6OjnjnnXd4 + 442fejzfm2/+POeTKQcHH7K5OeDw8PDx+wwGA4bDIVEU8cYbb/DOO+9wcXHB/v7+cqec/atx + fWNjgyiKOD8/5/z8nHfeeYeDgwP+4A//gA8++IDz4TlP7j9JGIYcHh5ycHDwePGPxuuvv85v + /MZvLMVH8sGHP2E4HGKxRFHEYLDJ0dEhcRyTJMlSUmK+9a1vcXR0SBSFDIfnjwlxcPABh4eH + j58TRRFHR0ePn/donm9+85scHR0hfue/+QeWz4b0f+6X+f9uCB7vrf1XqPuIK/+6EccJrVb0 + /+gJR0dH7O/v/5Xf8NH9jRew9jFlhsMhrVaLKIpIkoQoioiiiIuLC4DHxx/9/sscHQ6Hj+9/ + RIjBYJM4mZPEMRsbGwC8886fcevW/uP5H92fJDEXF8PHnGo42Obi4hyA/f19jo6OHp87ODhY + EkHQarUeS0GSxI+vaf4nbGxskCTJv/TuBwcHqF/7xl9/i+uEn4xmjMdjXNdlNBrx7rvv4jgO + Dx8+xPM84jimKIpGTw8bkXx4csrBwQe8/PLLHBwccHR0xObmJufn58RxwtHRIUdHh7hOU5vf + 29vj6OgI1/M5OrpHURR85zvf5bnnnmM8HvP222/z3HPPcXx8zHg8Zji84NNPP37sjQaDAcfH + x7RaLT755BOSJFleN2Rvb4/f/u1/xPPPP0dZlhwfH3NwcPD42kd2oCgKer3eY2apX/vGz7zF + dcr2a19+fMHm5iZ7e3sAbG5uPub6I86WZUm/32dvd5dWq/XY0CRJwmg0otVq0e/3iaKIvb09 + XNelKAqiKKIsS4oiZ3OwQasVcetWYxz7/f5jbrmuS6vVYnNz8JiLrVbTdXrEpH6/j+u6PPfc + cwgh6PV69Pt9xuMxRVHQarW4desWrusSRRGtVgshxONzQghc10X8zn/9n8LtK9v/+W/w/8Mh + /i957VpDfrfOMwAAAABJRU5ErkJggg==' + readStream) readStream) nextImage + ! Item was added: + ----- Method: WebCamMorph class>>initialize (in category 'class initialization') ----- + initialize + "CameraMorph initialize" + + + + ! Item was added: + ----- Method: WebCamMorph class>>resolutionFor: (in category 'scripting') ----- + resolutionFor: aSymbol + (#(low medium high hd) includes: aSymbol) ifFalse: [^ 320 at 240]. + + ^ {160 @ 120. 320 @ 240. 640 @ 480. 1280 @ 960} + at: (WebCamResolution resolutions indexOf: aSymbol) + ! Item was added: + ----- Method: WebCamMorph class>>shutDown (in category 'accessing') ----- + shutDown + self allOff. + ! Item was added: + ----- Method: WebCamMorph class>>startUp (in category 'accessing') ----- + startUp + "Try to bring up any instances that were on before shutdown" + ! Item was added: + ----- Method: WebCamMorph>>addCustomMenuItems:hand: (in category 'menu') ----- + addCustomMenuItems: aMenu hand: aHandMorph + + super addCustomMenuItems: aMenu hand: aHandMorph. + aMenu + addUpdating: #cameraToggleString action: #toggleCameraOnOff; + addLine; + add: 'resolution...' translated subMenu: ([:menu | + WebCamResolution resolutions do: [:res | + menu + add: (resolution == res ifTrue: [''] ifFalse: ['']), res translated + selector: #setWebCamResolution: + argument: res]. + menu] value: (aMenu class new defaultTarget: aMenu defaultTarget)); + add: 'orientation...' translated subMenu: ([:menu | + WebCamOrientation orientations do: [:ori | + menu + add: (orientation == ori ifTrue: [''] ifFalse: ['']), ori translated + selector: #setWebCamOrientation: + argument: ori]. + menu] value: (aMenu class new defaultTarget: aMenu defaultTarget)); + addUpdating: #frameSizeToggleString action: #toggleUseFrameSize; + addUpdating: #showFPSToggleString action: #toggleShowFPS; + yourself + ! Item was added: + ----- Method: WebCamMorph>>cameraIsOn (in category 'accessing') ----- + cameraIsOn + ^camIsOn! Item was added: + ----- Method: WebCamMorph>>cameraNumber (in category 'accessing') ----- + cameraNumber + ^camNum! Item was added: + ----- Method: WebCamMorph>>cameraNumber: (in category 'accessing') ----- + cameraNumber: anInteger + camNum ~= anInteger ifTrue: + [camNum := anInteger. + self initializeDisplayForm]! Item was added: + ----- Method: WebCamMorph>>cameraToggleString (in category 'menu') ----- + cameraToggleString + + ^ camIsOn + ifTrue: ['', 'turn camera off' translated] + ifFalse: ['', 'turn camera on' translated]. + + + + ! Item was added: + ----- Method: WebCamMorph>>decreaseCaptureDelay (in category 'accessing') ----- + decreaseCaptureDelay + + captureDelayMs := (captureDelayMs - 1) min: 200.! Item was added: + ----- Method: WebCamMorph>>delete (in category 'submorphs - add/remove') ----- + delete + self off. + super delete! Item was added: + ----- Method: WebCamMorph>>drawCameraImageOn: (in category 'drawing') ----- + drawCameraImageOn: aCanvas + | scale offset | + offset := 0 @ 0. + scale := 1 @ 1. + bounds extent = displayForm extent + ifFalse: [scale := bounds extent / displayForm extent]. + orientation == #natural + ifTrue: [ + scale := scale x negated @ scale y. + offset := bounds width @ 0]. + 1 @ 1 = scale + ifTrue: [aCanvas drawImage: displayForm at: bounds origin + offset] + ifFalse: [aCanvas + warpImage: displayForm + transform: (MatrixTransform2x3 withScale: scale) + at: bounds origin + offset]. + ! Item was added: + ----- Method: WebCamMorph>>drawFPSOn: (in category 'drawing') ----- + drawFPSOn: aCanvas + showFPS ifFalse: [^self]. + aCanvas + drawString: 'FPS: ', fps asString + at: bounds bottomLeft + (5 @ -20) + font: Preferences windowTitleFont + color: Color white! Item was added: + ----- Method: WebCamMorph>>drawOn: (in category 'drawing') ----- + drawOn: aCanvas + camIsOn ifFalse: + [self initializeDisplayForm. + self on]. + camIsOn ifTrue: + [(CameraInterface frameExtent: camNum) ~= displayForm extent ifTrue: + [self initializeDisplayForm]]. + displayForm ifNil: + [self initializeDisplayForm]. + useFrameSize ifTrue: [self extent: frameExtent]. + self drawCameraImageOn: aCanvas. + self drawFPSOn: aCanvas. + self drawOverlayTextOn: aCanvas! Item was added: + ----- Method: WebCamMorph>>drawOverlayTextOn: (in category 'drawing') ----- + drawOverlayTextOn: aCanvas + camIsOn ifTrue: [^self]. + aCanvas + drawString: 'Camera is off' translated + at: bounds origin + (5 @ 2) + font: Preferences windowTitleFont + color: Color white.! Item was added: + ----- Method: WebCamMorph>>frameSizeToggleString (in category 'menu') ----- + frameSizeToggleString + + ^ (useFrameSize ifTrue: [''] ifFalse: ['']), 'use frame size' translated + + + ! Item was added: + ----- Method: WebCamMorph>>getLastFrame (in category 'e-toy - settings') ----- + getLastFrame + + + ^ SketchMorph withForm: displayForm deepCopy! Item was added: + ----- Method: WebCamMorph>>getShowFPS (in category 'e-toy - settings') ----- + getShowFPS + ^ showFPS + ! Item was added: + ----- Method: WebCamMorph>>getUseFrameSize (in category 'e-toy - settings') ----- + getUseFrameSize + ^ useFrameSize + ! Item was added: + ----- Method: WebCamMorph>>getWebCamIsOn (in category 'e-toy - settings') ----- + getWebCamIsOn + + ^ camIsOn! Item was added: + ----- Method: WebCamMorph>>getWebCamResolution (in category 'e-toy - settings') ----- + getWebCamResolution + ^ resolution + + ! Item was added: + ----- Method: WebCamMorph>>increaseCaptureDelay (in category 'accessing') ----- + increaseCaptureDelay + + captureDelayMs := (captureDelayMs + 1) max: 10.! Item was added: + ----- Method: WebCamMorph>>initialize (in category 'initialization') ----- + initialize + super initialize. + camNum := 1. + camIsOn := false. + showFPS := false. + captureDelayMs := 16. "stepTime" + fps := 60. "guess." + lastDisplayTime := 0. + framesSinceLastDisplay := 0. + useFrameSize := false. + resolution := #medium. + orientation := #natural. + frameExtent := self class resolutionFor: resolution! Item was added: + ----- Method: WebCamMorph>>initializeDisplayForm (in category 'initialization') ----- + initializeDisplayForm + | cameraExtent formExtent | + + cameraExtent := CameraInterface frameExtent: camNum. + cameraExtent isZero + ifTrue: [formExtent := frameExtent] + ifFalse: [ | camRatio frameRatio | + formExtent := cameraExtent. + camRatio := cameraExtent x / cameraExtent y. + frameRatio := frameExtent x / frameExtent y. + camRatio ~= frameRatio ifTrue: [frameExtent := frameExtent x @ (frameExtent x * camRatio reciprocal)]]. + displayForm := Form extent: formExtent depth: 32. + self extent: frameExtent. + ! Item was added: + ----- Method: WebCamMorph>>intoWorld: (in category 'initialization') ----- + intoWorld: aWorld + + super intoWorld: aWorld. + camIsOn ifTrue: [self on] + ifFalse:[self off]. + self removeActionsForEvent: #aboutToEnterWorld. + aWorld + when: #aboutToLeaveWorld + send: #outOfWorld: + to: self + with: aWorld.! Item was added: + ----- Method: WebCamMorph>>knownName (in category 'testing') ----- + knownName + + ^ CameraInterface cameraName: camNum ! Item was added: + ----- Method: WebCamMorph>>nextFrame (in category 'stepping and presenter') ----- + nextFrame + + | frameCount | + frameCount := CameraInterface getFrameForCamera: camNum into: displayForm bits. + frameCount = 0 ifTrue: [self increaseCaptureDelay]. + frameCount > 2 ifTrue: [self decreaseCaptureDelay]. + framesSinceLastDisplay := framesSinceLastDisplay + frameCount! Item was added: + ----- Method: WebCamMorph>>off (in category 'accessing') ----- + off + self stopStepping. + camIsOn := false. + "Be careful not to close the camera if any other morphs are using the same camera." + (self class allInstances anySatisfy: [:wcm| wcm cameraNumber = camNum and: [wcm cameraIsOn]]) ifFalse: + [CameraInterface closeCamera: camNum]. + self changed + + "self allInstances select: [:wcm| wcm cameraNumber = 1 and: [wcm cameraIsOn]]"! Item was added: + ----- Method: WebCamMorph>>on (in category 'accessing') ----- + on + camIsOn ifTrue: [^true]. + (CameraInterface cameraIsOpen: camNum) ifFalse: + [(CameraInterface openCamera: camNum width: frameExtent x height: frameExtent y) ifNil: + [^false]]. + "The plugin/camera subsystem may end up choosing a different width and height. + So use the width and height it has selected; it may not be what was asked for." + self initializeDisplayForm. + CameraInterface waitForCameraStart: camNum. + camIsOn := true. + self startStepping! Item was added: + ----- Method: WebCamMorph>>outOfWorld: (in category 'initialization') ----- + outOfWorld: aWorld + + super outOfWorld: aWorld. + camIsOn ifTrue: [self off. camIsOn := true]. + aWorld + when: #aboutToEnterWorld + send: #intoWorld: + to: self + with: aWorld.! Item was added: + ----- Method: WebCamMorph>>setShowFPS: (in category 'e-toy - settings') ----- + setShowFPS: aBoolean + showFPS := aBoolean + ! Item was added: + ----- Method: WebCamMorph>>setUseFrameSize: (in category 'e-toy - settings') ----- + setUseFrameSize: aBoolean + useFrameSize := aBoolean! Item was added: + ----- Method: WebCamMorph>>setWebCamIsOn: (in category 'e-toy - settings') ----- + setWebCamIsOn: aBoolean + aBoolean ifTrue: [self on] ifFalse: [self off] + ! Item was added: + ----- Method: WebCamMorph>>setWebCamOrientation: (in category 'e-toy - settings') ----- + setWebCamOrientation: aSymbol + + ((WebCamOrientation orientations) includes: aSymbol) ifFalse: [^ self]. + orientation := aSymbol. + + + ! Item was added: + ----- Method: WebCamMorph>>setWebCamResolution: (in category 'e-toy - settings') ----- + setWebCamResolution: aSymbol + | wasOn | + "Failing silently here is awful; but that's what the code did :-(" + (WebCamResolution resolutions includes: aSymbol) ifFalse: [^ self]. + resolution := aSymbol. + + (wasOn := camIsOn) ifTrue: [self off]. + frameExtent := self class resolutionFor: aSymbol. + displayForm ifNotNil: + [displayForm := displayForm scaledToSize: frameExtent]. + self updateDisplay. + wasOn ifTrue: [self on] + ! Item was added: + ----- Method: WebCamMorph>>showFPSToggleString (in category 'menu') ----- + showFPSToggleString + + ^ (showFPS ifTrue: [''] ifFalse: ['']), 'show fps' translated + + + ! Item was added: + ----- Method: WebCamMorph>>step (in category 'stepping and presenter') ----- + step + camIsOn ifFalse:[self stopStepping]. + self updateDisplay. + + ! Item was added: + ----- Method: WebCamMorph>>stepTime (in category 'stepping and presenter') ----- + stepTime + "Answer the desired time between steps in milliseconds" + ^ captureDelayMs + ! Item was added: + ----- Method: WebCamMorph>>toggleCameraOnOff (in category 'menu') ----- + toggleCameraOnOff + camIsOn + ifTrue:[self off] + ifFalse:[self on]! Item was added: + ----- Method: WebCamMorph>>toggleShowFPS (in category 'menu') ----- + toggleShowFPS + + showFPS := showFPS not. + ! Item was added: + ----- Method: WebCamMorph>>toggleUseFrameSize (in category 'menu') ----- + toggleUseFrameSize + + useFrameSize := useFrameSize not. + ! Item was added: + ----- Method: WebCamMorph>>updateDisplay (in category 'stepping and presenter') ----- + updateDisplay + camIsOn ifTrue:[self nextFrame]. + self updateFPS. + self changed.! Item was added: + ----- Method: WebCamMorph>>updateFPS (in category 'stepping and presenter') ----- + updateFPS + + | now mSecs | + now := Time millisecondClockValue. + mSecs := now - lastDisplayTime. + (mSecs > 500 or: [mSecs < 0 "clock wrap-around"]) + ifTrue: [ + fps := (framesSinceLastDisplay * 1000) // mSecs. + lastDisplayTime := now. + framesSinceLastDisplay := 0].! Item was added: + SymbolListType subclass: #WebCamOrientation + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'MorphicExtras-WebCam'! Item was added: + ----- Method: WebCamOrientation class>>initialize (in category 'class initialization') ----- + initialize + + self addStandardVocabulary: self new.! Item was added: + ----- Method: WebCamOrientation class>>orientations (in category 'constants') ----- + orientations + ^ #( native natural )! Item was added: + ----- Method: WebCamOrientation class>>unload (in category 'class initialization') ----- + unload + + self allStandardVocabularies removeKey: self class name ifAbsent: [].! Item was added: + ----- Method: WebCamOrientation class>>vocabularyName (in category 'constants') ----- + vocabularyName + + ^ self name! Item was added: + ----- Method: WebCamOrientation>>initialize (in category 'initialization') ----- + initialize + super initialize. + self vocabularyName: self class vocabularyName. + + self symbols: self class orientations.! Item was added: + ----- Method: WebCamOrientation>>representsAType (in category 'tiles') ----- + representsAType + ^true! Item was added: + SymbolListType subclass: #WebCamResolution + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'MorphicExtras-WebCam'! Item was added: + ----- Method: WebCamResolution class>>initialize (in category 'class initialization') ----- + initialize + + self addStandardVocabulary: self new.! Item was added: + ----- Method: WebCamResolution class>>resolutions (in category 'constants') ----- + resolutions + ^ #(#'low' #'medium' #'high' #'hd') + ! Item was added: + ----- Method: WebCamResolution class>>vocabularyName (in category 'constants') ----- + vocabularyName + + ^ self name! Item was added: + ----- Method: WebCamResolution>>initialize (in category 'initialization') ----- + initialize + super initialize. + self vocabularyName: self class vocabularyName. + + self symbols: self class resolutions + ! Item was added: + ----- Method: WebCamResolution>>representsAType (in category 'tiles') ----- + representsAType + ^true! From commits at source.squeak.org Wed Mar 17 14:26:47 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:26:47 0000 Subject: [squeak-dev] The Trunk: EToys-mt.436.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.436.mcz ==================== Summary ==================== Name: EToys-mt.436 Author: mt Time: 17 March 2021, 3:26:41.577151 pm UUID: 70827cb5-0a4a-e249-81d1-53d77610df40 Ancestors: EToys-mt.435 Separate move from extension to make merging work without conflicts. Complements EToys-mt.435. =============== Diff against EToys-mt.435 =============== Item was removed: - ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category '*Etoys-defaults') ----- - addExtraItemsToMenu: aMenu forSlotSymbol: slotSym - "If the receiver has extra menu items to add to the slot menu, here is its chance to do it. The defaultTarget of the menu is the player concerned." - - aMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym. - aMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated! Item was removed: - ----- Method: PointType>>defaultArgumentTile (in category '*Etoys-defaults') ----- - defaultArgumentTile - "Answer a tile to represent the type" - - ^ (0 at 0) newTileMorphRepresentative typeColor: self typeColor! Item was removed: - ----- Method: PointType>>newReadoutTile (in category '*Etoys-tiles') ----- - newReadoutTile - "Answer a tile that can serve as a readout for data of this type" - - | aTile | - aTile := NumericReadoutTile new typeColor: Color lightGray lighter. - aTile setProperty: #PointValued toValue: true. - ^ aTile! Item was removed: - ----- Method: PointType>>wantsArrowsOnTiles (in category '*Etoys-defaults') ----- - wantsArrowsOnTiles - "Answer whether this data type wants up/down arrows on tiles representing its values" - - ^ false! Item was removed: - ----- Method: PointType>>wantsAssignmentTileVariants (in category '*Etoys-tiles') ----- - wantsAssignmentTileVariants - "Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by." - - ^ true! Item was removed: - ----- Method: PointType>>wantsSuffixArrow (in category '*Etoys-defaults') ----- - wantsSuffixArrow - "Answer whether a tile showing data of this type would like to have a suffix arrow" - - ^ true! From commits at source.squeak.org Wed Mar 17 14:27:19 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:27:19 0000 Subject: [squeak-dev] The Trunk: Protocols-mt.79.mcz Message-ID: Marcel Taeumel uploaded a new version of Protocols to project The Trunk: http://source.squeak.org/trunk/Protocols-mt.79.mcz ==================== Summary ==================== Name: Protocols-mt.79 Author: mt Time: 17 March 2021, 3:27:19.172151 pm UUID: 453175b7-7cea-504a-85cc-e6e36c15562f Ancestors: Protocols-mt.78 Separate move from extension to make merging work without conflicts. Complements EToys-mt.435. =============== Diff against Protocols-mt.78 =============== Item was added: + ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category 'defaults') ----- + addExtraItemsToMenu: aMenu forSlotSymbol: slotSym + "If the receiver has extra menu items to add to the slot menu, here is its chance to do it. The defaultTarget of the menu is the player concerned." + + aMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym. + aMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated! Item was added: + ----- Method: PointType>>defaultArgumentTile (in category 'defaults') ----- + defaultArgumentTile + "Answer a tile to represent the type" + + ^ (0 at 0) newTileMorphRepresentative typeColor: self typeColor! Item was added: + ----- Method: PointType>>newReadoutTile (in category 'tiles') ----- + newReadoutTile + "Answer a tile that can serve as a readout for data of this type" + + | aTile | + aTile := NumericReadoutTile new typeColor: Color lightGray lighter. + aTile setProperty: #PointValued toValue: true. + ^ aTile! Item was added: + ----- Method: PointType>>wantsArrowsOnTiles (in category 'defaults') ----- + wantsArrowsOnTiles + "Answer whether this data type wants up/down arrows on tiles representing its values" + + ^ false! Item was added: + ----- Method: PointType>>wantsAssignmentTileVariants (in category 'tiles') ----- + wantsAssignmentTileVariants + "Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by." + + ^ true! Item was added: + ----- Method: PointType>>wantsSuffixArrow (in category 'defaults') ----- + wantsSuffixArrow + "Answer whether a tile showing data of this type would like to have a suffix arrow" + + ^ true! From commits at source.squeak.org Wed Mar 17 14:33:16 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:33:16 0000 Subject: [squeak-dev] The Trunk: EToys-mt.437.mcz Message-ID: Marcel Taeumel uploaded a new version of EToys to project The Trunk: http://source.squeak.org/trunk/EToys-mt.437.mcz ==================== Summary ==================== Name: EToys-mt.437 Author: mt Time: 17 March 2021, 3:33:10.117151 pm UUID: 3e0cca35-eab1-1044-9064-1fb1a1d4a14f Ancestors: EToys-mt.436 Try again to separate EToys-specific stuff from PointType. Complements EToys-mt.435 =============== Diff against EToys-mt.436 =============== Item was added: + ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category '*EToys-defaults') ----- + addExtraItemsToMenu: aMenu forSlotSymbol: slotSym + "If the receiver has extra menu items to add to the slot menu, here is its chance to do it. The defaultTarget of the menu is the player concerned." + + aMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym. + aMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated! Item was added: + ----- Method: PointType>>defaultArgumentTile (in category '*EToys-defaults') ----- + defaultArgumentTile + "Answer a tile to represent the type" + + ^ (0 at 0) newTileMorphRepresentative typeColor: self typeColor! Item was added: + ----- Method: PointType>>newReadoutTile (in category '*EToys-tiles') ----- + newReadoutTile + "Answer a tile that can serve as a readout for data of this type" + + | aTile | + aTile := NumericReadoutTile new typeColor: Color lightGray lighter. + aTile setProperty: #PointValued toValue: true. + ^ aTile! Item was added: + ----- Method: PointType>>wantsArrowsOnTiles (in category '*EToys-defaults') ----- + wantsArrowsOnTiles + "Answer whether this data type wants up/down arrows on tiles representing its values" + + ^ false! Item was added: + ----- Method: PointType>>wantsAssignmentTileVariants (in category '*EToys-tiles') ----- + wantsAssignmentTileVariants + "Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by." + + ^ true! Item was added: + ----- Method: PointType>>wantsSuffixArrow (in category '*EToys-defaults') ----- + wantsSuffixArrow + "Answer whether a tile showing data of this type would like to have a suffix arrow" + + ^ true! From commits at source.squeak.org Wed Mar 17 14:33:50 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 17 Mar 2021 14:33:50 0000 Subject: [squeak-dev] The Trunk: Protocols-mt.80.mcz Message-ID: Marcel Taeumel uploaded a new version of Protocols to project The Trunk: http://source.squeak.org/trunk/Protocols-mt.80.mcz ==================== Summary ==================== Name: Protocols-mt.80 Author: mt Time: 17 March 2021, 3:33:50.195151 pm UUID: a6762782-16e2-2a4f-aa74-7f7b3eb2080e Ancestors: Protocols-mt.79 Try again to separate EToys-specific stuff from PointType. Complements EToys-mt.435 =============== Diff against Protocols-mt.79 =============== Item was removed: - ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category 'defaults') ----- - addExtraItemsToMenu: aMenu forSlotSymbol: slotSym - "If the receiver has extra menu items to add to the slot menu, here is its chance to do it. The defaultTarget of the menu is the player concerned." - - aMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym. - aMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated! Item was removed: - ----- Method: PointType>>defaultArgumentTile (in category 'defaults') ----- - defaultArgumentTile - "Answer a tile to represent the type" - - ^ (0 at 0) newTileMorphRepresentative typeColor: self typeColor! Item was removed: - ----- Method: PointType>>newReadoutTile (in category 'tiles') ----- - newReadoutTile - "Answer a tile that can serve as a readout for data of this type" - - | aTile | - aTile := NumericReadoutTile new typeColor: Color lightGray lighter. - aTile setProperty: #PointValued toValue: true. - ^ aTile! Item was removed: - ----- Method: PointType>>wantsArrowsOnTiles (in category 'defaults') ----- - wantsArrowsOnTiles - "Answer whether this data type wants up/down arrows on tiles representing its values" - - ^ false! Item was removed: - ----- Method: PointType>>wantsAssignmentTileVariants (in category 'tiles') ----- - wantsAssignmentTileVariants - "Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by." - - ^ true! Item was removed: - ----- Method: PointType>>wantsSuffixArrow (in category 'defaults') ----- - wantsSuffixArrow - "Answer whether a tile showing data of this type would like to have a suffix arrow" - - ^ true! From Yoshiki.Ohshima at acm.org Wed Mar 17 16:23:30 2021 From: Yoshiki.Ohshima at acm.org (Yoshiki Ohshima) Date: Wed, 17 Mar 2021 09:23:30 -0700 Subject: [squeak-dev] [ANN] SimulationStudio and sandboxed execution for Squeak In-Reply-To: <3d123ad21ef14d4d8c13d34701afe72c@student.hpi.uni-potsdam.de> References: <17a9f70a532c46299813f6955122a9c2@student.hpi.uni-potsdam.de> <56366534133d4e13b6b75c7f9afd45eb@student.hpi.uni-potsdam.de> <85bf102f74fe40e5af41ed73f452e87c@student.hpi.uni-potsdam.de> <3d123ad21ef14d4d8c13d34701afe72c@student.hpi.uni-potsdam.de> Message-ID: It is great to hear that image is working there. Yes, in the current implementation, things have to use the custom compiler to hook the action. It is, though, conceivable to make Object be Worlds-aware and all objects would behave that way... (including the data structure that supports the Worlds mechanism, or not!), except all primitives that simply write data into objects. The JS implementation is a bit different and it compiles a given program into a Worlds-aware form. Aran Lunzer found that the simple approach has some unexpected behavior, and he and I wrote a report on it and how to mitigate it. It might be of your interest: http://www.vpri.org/pdf/m2013002_experiments.pdf On Wed, Mar 17, 2021 at 6:29 AM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Hi Marcel, > > > ah, that was missing! Thank you. :-) > > Some first impressions of the Worlds implementation for Squeak: If I > understand correctly, it only works with objects that explicitly support > the worlds mechanism. So for example: > > z := #(1). > world := WWorld thisWorld sprout. > {world eval: [ > z at: 1 put: 2. > z]. > z} "==> #(#(2) #(2)) > > Sandbox would answer: > > z := #(1). > {Sandbox evaluate: [ > z at: 1 put: 2. > z]. > z} "==> #(#(2) #(1))" > > For Worlds, I apparently would need to use a specialized WArray instead. > This has the advantage of being much faster than Sandbox but also the > disadvantage of not fitting for general-purpose Smalltalk expressions. > Still, a very interesting approach! > > Best, > Christoph > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Taeumel, Marcel > *Gesendet:* Mittwoch, 17. März 2021 14:12:12 > *An:* squeak-dev > *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > Hi Christoph. > > > How am I supposed to tell the VM which image file to load? It always > wants to open the Squeak4.4-12327.image file only. > > Change the .ini file :-) Remove the hard-coded path in there. > > > The message above is a result of replacing the default image and > changes file in the AllInOne bundle with frank.image and frank.changes. > > I suppose you need the other DLLs and resources, too? What I tried was to > copy the VM files over to the contents from the ZIP file. That worked. :-) > > Best, > Marcel > > Am 17.03.2021 14:06:05 schrieb Thiede, Christoph < > christoph.thiede at student.hpi.uni-potsdam.de>: > > Hi Marcel, > > > it's not working for me: > > > --------------------------- > Squeak! > --------------------------- > Could not open the Squeak image file > 'C:\Users\Christoph\OneDrive\Downloads\Squeak-4.4-All-in-One\Squeak-4.4-All-in-One.app\Contents\Resources\Squeak4.4-12327.image' > > There are several ways to open an image file. You can: > 1. Double-click on the desired image file. > 2. Drop the image file onto the application. > Aborting... > > --------------------------- > OK > --------------------------- > > How am I supposed to tell the VM which image file to load? It always wants > to open the Squeak4.4-12327.image file only. Dropping another image file on > the executable only gives me a load error from within the 4.4 image. The > message above is a result of replacing the default image and changes file > in the AllInOne bundle with frank.image and frank.changes. > > > Best, > > Christoph > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Taeumel, Marcel > *Gesendet:* Mittwoch, 17. März 2021 09:13:04 > *An:* squeak-dev > *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > Hi Christoph. > > > Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load > Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. > > Frank-170908 is based on Squeak 4.4 alpha. The VM from the Squeak 4.4 > release works fine under Windows 10: http://files.squeak.org/4.4/ > > Best, > Marcel > > Am 17.03.2021 01:36:08 schrieb Thiede, Christoph < > christoph.thiede at student.hpi.uni-potsdam.de>: > > Hm, the 4.1 4.2 4.3 VMs refuse to open this image. I also tried to load > Grease-yo.69.mcz into a fresh 4.2 image but it hangs up as well. > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Yoshiki Ohshima > *Gesendet:* Mittwoch, 17. März 2021 01:02:26 > *An:* The general-purpose Squeak developers list > *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed > execution for Squeak > > It was created on Squeak4.2, Squeak4.4, etc. I think this one has stuff > preloaded: > > tinlizzie.org/~ohshima/Frank-170908.zip > > And you need to find a VM something along the line of: > > 'Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.56] Croquet Cog > 4.0.0' > > Let me (us) know if you have more questions! > > On Tue, Mar 16, 2021 at 4:39 PM Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > >> My image hangs when loading Greases ... Can you recommend an older >> version of Squeak which is officially supported? :-) >> >> >> Best, >> >> Christoph >> >> ------------------------------ >> *Von:* Squeak-dev im >> Auftrag von Yoshiki Ohshima >> *Gesendet:* Mittwoch, 17. März 2021 00:20:53 >> *An:* The general-purpose Squeak developers list >> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >> execution for Squeak >> >> W2Compiler, right? It took sometime to dig it up but it is in the Grease >> package in the directory. The main things is to compile AssingmentNode >> into a message call, and to avoid conflict such accessors were prefiexed >> with "wiv666" ("world instance variable 666") The majority of job is done >> by the W2Parser. >> >> On Tue, Mar 16, 2021 at 3:55 PM Thiede, Christoph < >> Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: >> >>> Thanks! Unfortunately, it's referring to a WCompiler which apparently is >>> not part of the mcz file ... >>> >>> >>> Best, >>> >>> Christoph >>> >>> ------------------------------ >>> *Von:* Squeak-dev im >>> Auftrag von Yoshiki Ohshima >>> *Gesendet:* Dienstag, 16. März 2021 23:48:52 >>> *An:* Vanessa Freudenberg >>> *Cc:* The general-purpose Squeak developers list >>> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >>> execution for Squeak >>> >>> Hi! >>> >>> We still maintain the packages from VPRI. Looking at the directory, we >>> have quite a few versions of Worlds. So there is a chance that it does >>> something. >>> >>> http://tinlizzie.org/updates/exploratory/packages/ >>> >>> On Tue, Mar 16, 2021 at 1:59 PM Vanessa Freudenberg < >>> vanessa at codefrau.net> wrote: >>> >>>> On Tue, Mar 16, 2021 at 9:52 AM Thiede, Christoph < >>>> Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: >>>> >>>>> One more question: Do you know where I can find the Smalltalk >>>>> implementation of worlds? Is there any at all? The abstract in ResearchGate >>>>> mentions this but is not addressed in the paper ... >>>>> >>>> Well luckily one of the authors is still on this list ... >>>> >>>> Looks really interesting and useful! >>>> >>>> Vanessa >>>> >>>>> Best, >>>>> >>>>> Christoph >>>>> >>>>> ------------------------------ >>>>> *Von:* Thiede, Christoph >>>>> *Gesendet:* Dienstag, 16. März 2021 15:10:37 >>>>> *An:* squeak-dev at lists.squeakfoundation.org >>>>> *Betreff:* AW: [squeak-dev] [ANN] SimulationStudio and sandboxed >>>>> execution for Squeak >>>>> >>>>> >>>>> Hi Subbu, thanks a lot for your thoughts! :-) >>>>> >>>>> >>>>> > I am not sure if you have read Warth's research at VPRI >>>>> >>>>> >>>>> No, I have not. Looks very interesting, I will read this! >>>>> >>>>> The only literature I had found on this (I have to admit that I did >>>>> not spend much time on research) was this one: >>>>> https://wiki.squeak.org/squeak/uploads/2074/sandbox.pdf It mentions a >>>>> number of problems but does not come up with a simulation solution, so it >>>>> would exclusively lock your image, I guess. >>>>> >>>>> > I expect efficiency to improve if VM (e.g. object memory) exposes primitives >>>>> for object spaces with copy-on-write and white-outs (for objects >>>>> finalized in child space but not in parent). A sandbox could carve >>>>> out an object space to hold modified/deleted objects and then either >>>>> commit to parent or dispose it off on close. ObjectMemory already has >>>>> support for multiple spaces (e.g. old and young). It needs to be exposed, >>>>> with lots of care, to ST-side code. >>>>> >>>>> Yeah, integrating the sandbox partially into the VM would make things >>>>> faster, of course ... I haven't made any attempts in this direction for two >>>>> reasons: First because I, honestly, still did not find the time for getting >>>>> started with VMMaker, and second because while I know that the VM is >>>>> written in a Smalltalk dialect as well, it hurts me a bit that it lacks the >>>>> liveness of manipulating everything from within the running image. By the >>>>> way, is there already some research about unioning these two worlds in >>>>> order to reprogram the VM from within the image that is running in it? I >>>>> would love this. >>>>> >>>>> What are white-outs? I could not find any reference on this. >>>>> >>>>> > Handling primitives, particularly those that involve physical i/o, >>>>> is a difficult problem. This is typically solved by using >>>>> virtualization and double buffering (e.g. display or input). It is ok >>>>> to work with non-volatile state variables for the first cut and then >>>>> introduce virtualization for transactional access. >>>>> >>>>> Actually, my current Sandbox approach does not even intend to "commit" >>>>> changes back to the rest of the image (rather to work like a Docker >>>>> container in small). Thus my goal would rather be to virtualize all >>>>> physical operations but keeping the effects back from the real physical >>>>> devices. For filesystem accesses, for example, I thought about redirecting >>>>> all write operations to a copy of the files in a special folder ... Not >>>>> sure how far this approach would work well, though. >>>>> >>>>> For some I/O primitives, however, virtualization is rather easy. For >>>>> example, when writing on the global Display, you can simply copy this >>>>> object like any other object into your sandbox space/world. However, other >>>>> primitives, such as from the FilePlugin, operate on state is managed >>>>> outside of the image ... >>>>> >>>>> Best, >>>>> Christoph >>>>> >>>>> ------------------------------ >>>>> *Von:* Squeak-dev im >>>>> Auftrag von K K Subbu >>>>> *Gesendet:* Dienstag, 16. März 2021 14:21:16 >>>>> *An:* squeak-dev at lists.squeakfoundation.org >>>>> *Betreff:* Re: [squeak-dev] [ANN] SimulationStudio and sandboxed >>>>> execution for Squeak >>>>> >>>>> >>>>> On 16/03/21 4:51 pm, Thiede, Christoph wrote: >>>>> > Hi all! :-) >>>>> > >>>>> > >>>>> > I'm very excited to finally share my new project with you today, >>>>> which I >>>>> > call *SimulationStudio* and have made available on GitHub under [1]. >>>>> Its >>>>> > primary function is to provide an inheritable >>>>> > *SimulationContext* subclass of Context that makes it easy to >>>>> simulate >>>>> > entire call trees while customizing the execution or installing >>>>> custom >>>>> > hooks for various tracing and measurement purposes. Another >>>>> > accomplishment is the *Sandbox* which allows you to run arbitrary >>>>> > Smalltalk code in an isolated environment, separating any side >>>>> effects >>>>> > that occur during the simulation from the rest of the image. >>>>> >>>>> This is an amazing development! >>>>> >>>>> I am not sure if you have read Warth's research at VPRI: >>>>> >>>>> World: Controlling the Scope of Side Effects by A Warth et. all, >>>>> >>>>> >>>>> >>>>> https://www.researchgate.net/publication/221496497_Worlds_Controlling_the_Scope_of_Side_Effects >>>>> >>>>> Worlds is like your Sandbox. It also had a commit method to propagate >>>>> state changes from the child to the parent. This is useful when a >>>>> method >>>>> modifies multiple state variables subject to strong invariants. A >>>>> method >>>>> may open a World, make changes and then verify invariants are >>>>> preserved >>>>> before committing the changes and closing the World. >>>>> >>>>> > *Limitations and challenges* >>>>> > >>>>> > Well, first of all ... *performance.* :-) Some recent measurements >>>>> that >>>>> > I have run have shown that the simulator reaches about 0.1 percent >>>>> (sic) >>>>> > of the speed of the VM executor, depending on the domain and the >>>>> > distribution of bytecode operations. >>>>> >>>>> I expect efficiency to improve if VM (e.g. object memory) exposes >>>>> primitives for object spaces with copy-on-write and white-outs (for >>>>> objects finalized in child space but not in parent). A sandbox could >>>>> carve out an object space to hold modified/deleted objects and then >>>>> either commit to parent or dispose it off on close. ObjectMemory >>>>> already >>>>> has support for multiple spaces (e.g. old and young). It needs to be >>>>> exposed, with lots of care, to ST-side code. >>>>> >>>>> > Another challenge is the *handling of primitive operations* during >>>>> the >>>>> > sandbox execution. >>>>> >>>>> Handling primitives, particularly those that involve physical i/o, is >>>>> a >>>>> difficult problem. This is typically solved by using virtualization >>>>> and >>>>> double buffering (e.g. display or input). It is ok to work with >>>>> non-volatile state variables for the first cut and then introduce >>>>> virtualization for transactional access. >>>>> >>>>> Regards .. Subbu >>>>> >>>>> >>>>> >>> >>> -- >>> -- Yoshiki >>> >>> >>> >> >> -- >> -- Yoshiki >> >> >> > > -- > -- Yoshiki > > > -- -- Yoshiki -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.jpg Type: image/jpeg Size: 158298 bytes Desc: not available URL: From lecteur at zogotounga.net Wed Mar 17 16:42:38 2021 From: lecteur at zogotounga.net (=?UTF-8?Q?St=c3=a9phane_Rollandin?=) Date: Wed, 17 Mar 2021 17:42:38 +0100 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <4dec21eb-bd19-187f-907f-7cad830c3e3c@gmx.net> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> <4dec21eb-bd19-187f-907f-7cad830c3e3c@gmx.net> Message-ID: <5c1d19ab-53fe-35d9-a0fa-898be66cd66a@zogotounga.net> > Impressive! As an outer world person I looked through the site but > didn't find any Screenshots. *I'd like to see the UI you're working in, > be it a lot of workspaces.* My UI usually is inspectors / explorers on > Objects with messages I send to them. Sometimes just some buttons placed > in the World. Making a GUI often is more than doubling the effort. Attached: P1.png shows the graph of song parts, each in a box, and an explorer opened on the first of these boxes from where the composition final tweaks are performed via plain code. P2.png shows the contents of one of the boxes. The upper window is a score editor with several melodic line generators, the bottom left window is a projection playground which is the killer technology I am proud to have invented about twenty years ago now, and where raw melodic structures are generated, to be further processed by the above mentioned melodic line generators. So there is not a single UI, but instead multiple editors referencing each other. The navigation is heavily driven by rich menus that can be interactively destructured to yield buttons and sets of controls such as the "prototype setting" sliders in P2.png. But mostly it is a mess. Stef -------------- next part -------------- A non-text attachment was scrubbed... Name: P1.png Type: image/png Size: 685427 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: P2.png Type: image/png Size: 598842 bytes Desc: not available URL: From m at jaromir.net Wed Mar 17 16:48:16 2021 From: m at jaromir.net (Jaromir Matas) Date: Wed, 17 Mar 2021 11:48:16 -0500 (CDT) Subject: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) In-Reply-To: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> References: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> Message-ID: <1615999696908-0.post@n4.nabble.com> Hi Christoph, the telegram Squeak bot is amazing :) A question: "Control primitives are disabled in sandbox simulation" not allowing forking, yielding etc. - is it just a precaution or some fundamental limitation? Thanks! ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 17 17:01:38 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 17 Mar 2021 17:01:38 +0000 Subject: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) In-Reply-To: <1615999696908-0.post@n4.nabble.com> References: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de>, <1615999696908-0.post@n4.nabble.com> Message-ID: <0ea589127bf64bfebd6e496591ca1c99@student.hpi.uni-potsdam.de> Hi Jaromir, thank you for giving it a try, glad you like it! :-) I would call it precaution. If you would host the bot yourself, you could change TelegramSmalltalkSession >> #isolationEnabled to access your real image without any limitations. But since @SqueakSmalltalkBot can be accessed by anyone and at the same time is hosted in my private network, it was crucial for me to carefully eliminate all kinds of side effects. For controlling operations such as forking and suspending, there is not yet any simulation support on the image side, which would potentially allow you to break out of my Sandbox and hack into my smart home system or anything else. :-) Thus I have disabled all the controlling primitives in the sandbox simulation for now (you can read more details about this in [1] if you are interested). But it's an interesting topic. It would be nice if we could simulate process controlling and scheduling in Squeak as well. Sounds like another exciting project ... :-) Best, Christoph [1] https://github.com/LinqLover/SimulationStudio/blob/a05f395d67a84a457c8224edadf03e3da80e17da/packages/SimulationStudio-Sandbox.package/SandboxContext.class/instance/doPrimitive.method.receiver.args..st#L44 ________________________________ Von: Squeak-dev im Auftrag von Jaromir Matas Gesendet: Mittwoch, 17. März 2021 17:48:16 An: squeak-dev at lists.squeakfoundation.org Betreff: Re: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) Hi Christoph, the telegram Squeak bot is amazing :) A question: "Control primitives are disabled in sandbox simulation" not allowing forking, yielding etc. - is it just a precaution or some fundamental limitation? Thanks! ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From herbertkoenig at gmx.net Wed Mar 17 18:20:16 2021 From: herbertkoenig at gmx.net (=?UTF-8?Q?Herbert_K=c3=b6nig?=) Date: Wed, 17 Mar 2021 19:20:16 +0100 Subject: [squeak-dev] [OT] some Squeak music In-Reply-To: <5c1d19ab-53fe-35d9-a0fa-898be66cd66a@zogotounga.net> References: <649fd748-e6dd-c1bc-344b-ecad862d5899@zogotounga.net> <4dec21eb-bd19-187f-907f-7cad830c3e3c@gmx.net> <5c1d19ab-53fe-35d9-a0fa-898be66cd66a@zogotounga.net> Message-ID: <89fb8e5f-d4f0-8694-d9ce-270c3862027d@gmx.net> Thank's Stef, I like it. For sure I lack the knowledge to understand the 'killer technology' but I know nothing about composition :-) Cheers, Herbert Am 17.03.2021 um 17:42 schrieb Stéphane Rollandin: >> Impressive! As an outer world person I looked through the site but >> didn't find any Screenshots. *I'd like to see the UI you're working >> in, be it a lot of workspaces.* My UI usually is inspectors / >> explorers on Objects with messages I send to them. Sometimes just >> some buttons placed in the World. Making a GUI often is more than >> doubling the effort. > > Attached: > > P1.png shows the graph of song parts, each in a box, and an explorer > opened on the first of these boxes from where the composition final > tweaks are performed via plain code. > > P2.png shows the contents of one of the boxes. The upper window is a > score editor with several melodic line generators, the bottom left > window is a projection playground which is the killer technology I am > proud to have invented about twenty years ago now, and where raw > melodic structures are generated, to be further processed by the above > mentioned melodic line generators. > > So there is not a single UI, but instead multiple editors referencing > each other. The navigation is heavily driven by rich menus that can be > interactively destructured to yield buttons and sets of controls such > as the "prototype setting" sliders in P2.png. > > But mostly it is a mess. > > Stef > -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Wed Mar 17 20:08:06 2021 From: m at jaromir.net (Jaromir Matas) Date: Wed, 17 Mar 2021 15:08:06 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1615901797162-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> <1615901797162-0.post@n4.nabble.com> Message-ID: <1616011686241-0.post@n4.nabble.com> Hi Christoph, Marcel, Thanks for your feedback! I'm responding jointly also to your Debugger post... again, apologies for mixing this up with your genuine process work :) > The only exception from this rule appears to occur when the Processor >> > #evaluate:onBehalfOf: logic does not get unwound correctly so the > effectiveProcess is not reset, which is a consequence of the bug I > described > [here]. Exactly, and that's precisely why I thought it was serious because the bug made discovering itself so much harder :) This is when one really needs to be aware of the genuine process and what it is doing. > [...] after terminating it, the debugged process keeps answering false > when sent > #isTerminated. I think this is also related to the thread you started in > [3] Yes, isTerminated (and isSuspended) is fixed by Kernel-jar.1381.mcz in [4]. I'd like to consider it a 'baby step' towards more refined versions in [2] or [3] you mentioned. >> What is the expected semantics of the Debugger's Abandon? To quit and do >> nothing more to the debugged process or continue unwinding? > I have to agree with Levente here that unwinding should not be skipped > here > definitively. Oh, absolutely! I managed to throw the baby out with the bathwater spectacularly :) > IMHO Debugger >> #abandon should have exactly the same effect as Process > >> #terminate. Yes, that's my feeling as well now (although I'm not in a position to give opinions; I have to go back and study the exceptions again more thoroughly). The examples I gave (without the non-local return) are not as nasty as your non-local return example: The main difference between your non-local example: [self error: 'e1'] ensure: [^2] and my one without the non-local return: [self error: 'e1'] ensure: [self error: 'e2'] is that in your case the ^2 interrupts the orderly unwinding/termination and the UI process continues as if still in simulation (because of the missed effective process reset) - until another exception happens *somewhen* in the future - while in my examples the next exception resetting the effectiveProcess happens right away in the ensure block, presenting "only" the Unwind error on the outside. And on top of that, in your case the image is in such a bad state that running Process or Semaphore tests even crash the image! > I wonder whether we can and whether we should find a way to heal > processes again after a missing reset [of the effectiveProcess]. Very interesting question indeed! To summarize: the non-local return in the ensure block causes a major disruption to the flow of control. Indeed the easiest and probably reasonable solution is to somehow prohibit non-local returns in the ensure blocks. This scenario, however uncovers a weakness in the #isTerminated, reporting the currently executing process with effectiveProcess assigned, as terminated and as a result preventing Process Browser to reveal such a pathological situation (which is precisely when you need to see it). Best regards, PS: For debugging this issue I tweaked my #isTerminated with the first line conditon reading: (self isActiveProcess or: [self effectiveProcess == Processor activeProcess]) ifTrue: [^ false]. instead of just self isActiveProcess ifTrue: [^ false]. to make the genuine process always visible... [1] http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-tp5127684p5127807.html [2] http://forum.world.st/The-Inbox-Kernel-jar-1377-mcz-tp5127438.html [3] http://forum.world.st/Refactoring-terminate-to-get-rid-of-cannot-return-errors-etc-td5127732.html [4] http://forum.world.st/The-Inbox-Kernel-jar-1381-mcz-tp5127665.html ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From squeaklist at gmail.com Thu Mar 18 17:06:07 2021 From: squeaklist at gmail.com (Kjell Godo) Date: Thu, 18 Mar 2021 10:06:07 -0700 Subject: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) In-Reply-To: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> References: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> Message-ID: +10 On Wed, Mar 17, 2021 at 05:32 Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Hi all! > > > After announcing SimulationStudio and Sandbox yesterday [3], today I'm > happy to introduce you to two other repositories which I have been working > at during the last months. Last week, I had the pleasure to present them > during the German Squeak Winter Demos [4]. Drum roll, say hello to > TelegramBot [1] & TelegramSmalltalkBot [2]! :-) > > > *TelegramBot* is a small framework I built to make it possible to > implement bots for the Telegram messenger [5]. It uses the official > Telegram Bot REST API [6] and maps it to an object-oriented design in > Squeak, providing support for different bot capabilities such as message > sending, receiving, and editing. It also allows sending multi-media message > types such as pictures (Forms), formatted messages (Texts), audio messages > (AbstractSounds), and some others. Last but not least, it comprises a > small API to host your bots in a background process of the image. For more > information, check out the README.md of the repository in [1]. > > > *TelegramSmalltalkBot* is a second repository that implements a Telegram > bot for evaluating Smalltalk expressions by using the TelegramBot framework > from above. Do you know this situation when you wonder "how does XYZ work > in Squeak" and cannot check it out because you do not have any PC or laptop > at hand right now? This situation is history as of today, just send a > message to the bot from wherever you are, just using your phone or even > your watch! In a nutshell, TelegramSmalltalkBot is a simple REPL shell that > utilizes the Squeak Compiler, but it's also packed with a number of > convenient features that make remote access to your image much more > pleasant. For example, the bot does not only answer plain text but also > multi-media messages such as pictures or files depending on the results of > your expressions. You can also use Workspace-like variable bindings or > reply to older messages from the bot to bind the receiver of your message. > For an exhaustive list of all features, visit the repository in [2] or just > send /help to the bot. I also have uploaded a short video demo about it at > [7]. > > > Another important thing to note is that TelegramSmalltalkBot is able to > evaluate every expression in a sandboxed execution environment by using the > SimulationStudio library I announced yesterday [3]. While both projects > have grown rather independently of each other, this usage fills an > important gap for me and I think it is a relevant real-world use case of > the Sandbox. > > > *Please try it out!** :-)* All you need is a Telegram account for free > and a client (Telegram is available cross-platform and can also be used > from the web). I am hosting an instance of the bot myself on my raspberry > pi and I feel confident enough about the isolation quality of my Sandbox > that I dare to unlock public access to the bot for everyone. A small > architecture diagram which I have shown at the Winter Demos is in the > attachments (contains clickable links to the repositories), you can also > find it in the wiki of [2]. > > > Just search in the Telegram app for *@SqueakSmalltalkBot* or follow this > link: https://t.me/SqueakSmalltalkBot [8] (QR code is also in the > attachments) > > > *I'm very much looking forward to your feedback!* If you experience any > problems or have new ideas, please let me know via squeak-dev or GitHub > issues! I'm already planning many new features for the bot - be sure to > watch the repository if you are interested in them. :-) > > > Best, > > Christoph > > > [1] https://github.com/LinqLover/TelegramBot > [2] https://github.com/LinqLover/TelegramSmalltalkBot > [3] > http://forum.world.st/ANN-SimulationStudio-and-sandboxed-execution-for-Squeak-td5127804.html > > [4] > http://forum.world.st/Squeak-Winter-Demos-2021-03-06-3-p-m-6-p-m-CET-virtual-tp5126913.html > [5] https://telegram.org > [6] https://core.telegram.org/bots/api > [7] https://youtu.be/HZCeThLqQmg > [8] https://t.me/SqueakSmalltalkBot > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eliot.miranda at gmail.com Thu Mar 18 19:20:25 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 18 Mar 2021 12:20:25 -0700 Subject: [squeak-dev] #testBecomeForward fails when simulated in a rush In-Reply-To: <95ef19eb17b04cc8919c770e957e6672@student.hpi.uni-potsdam.de> References: <5f2b013b71ac40009143e860a3fd7769@student.hpi.uni-potsdam.de> <95ef19eb17b04cc8919c770e957e6672@student.hpi.uni-potsdam.de> Message-ID: Hi Christoph, On Tue, Mar 16, 2021 at 3:23 PM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Hi Eliot, > > > thanks for fixing it! I still don't understand why the bug only occurred > during simulation, but glad you were able to find the cause. :-) > The normal VM is a JIT VM. That VM has JIT versions of some primitives, and in particular it has JIT versions of the #== and #~~ primitives. These primitives were correct, hiding the bugs in the interpreter versions. The first time the JIT VM sends a particular message (more accurately if it sends a message and the target method is not in the interpreter's method lookup cache) the VM interprets the method. The next time, because the method is in the interpreter's method lookup cache, the method will be JITTED and the machine code will be executed. So the interpreter version of #== and #~~ are only executed once each early in system startup. From then on the JIT version is used. In simulation primitives are evaluated via the tryPrimitive:withArguments: primitive and this primitive always runs the interpreter's version of a primitive. Hence in simulation one is always using the interpreter's primitives and so one sees the bug. > > > Best, > Christoph > ------------------------------ > *Von:* Squeak-dev im > Auftrag von Eliot Miranda > *Gesendet:* Dienstag, 16. März 2021 20:43:41 > *An:* The general-purpose Squeak developers list > *Betreff:* Re: [squeak-dev] #testBecomeForward fails when simulated in a > rush > > Hi Christoph, > > On Sun, Mar 14, 2021 at 8:48 AM Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > >> Hi all, >> >> >> it's Sunday afternoon (at least in my timezone :D) and here's an >> interesting weekend issue for you, maybe even a bug in the VM: >> >> >> p := [ObjectTest new testBecomeForward] newProcess. >> p runUntil: [:c | c isDead]. >> >> In my fresh trunk image, this expression always fails, i.e. a TestFailure >> is raised from the second assertion in the test, pt3 == pt2. >> >> However, when running the test normally, i.e. executing the first block >> without simulation, the test passes as expected. >> Also, when I try to debug the simulation, the test passes again. >> >> But I even inserted a halt around the (pt3 == pt2) and could see that it >> actually evaluated to false. >> >> >> And when I change the expression like this, it suddenly passes: >> >> >> p := [ObjectTest new testBecomeForward] newProcess. >> p runUntil: [:c | Smalltalk garbageCollect. c isDead]. >> >> What is this? Does the VM require some kind of memory sweep before the >> object identity consistency is restored again? To me, this looks pretty >> suspicious at least. >> > > Thank you. You've found a bug in the interpreted version of primitive > 110. It read > > primitiveIdentical > "is the receiver/first argument the same object as the (last) argument?. > pop argumentCount because this can be used as a mirror primitive." > | thisObject otherObject | > otherObject := self stackValue: 1. > thisObject := self stackTop. > ((objectMemory isOopForwarded: otherObject) > or: [argumentCount > 1 > and: [objectMemory isOopForwarded: thisObject]]) > ifTrue: > [self primitiveFailFor: PrimErrBadArgument] > ifFalse: > [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] > > but this is the wrong way around. It should read > > primitiveIdentical > "is the receiver/first argument the same object as the (last) argument?. > pop argumentCount because this can be used as a mirror primitive." > | thisObject otherObject | > thisObject := self stackValue: 1. > otherObject := self stackTop. > ((objectMemory isOopForwarded: otherObject) > or: [argumentCount > 1 > and: [objectMemory isOopForwarded: thisObject]]) > ifTrue: > [self primitiveFailFor: PrimErrBadArgument] > ifFalse: > [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] > > The invariant on invoking a primitive is that the receiver is > unforwarded. This is because it being the receiver of the message, the > message send machinery ensures it is not forwarded (if it was, the cached > message send logic would fail, and the slow lookup path checks for a > forwarded receiver, unforwarding and repeating the send if so). But > primitive arguments could be forwarded. So primitiveIdentical must check > for a potentially forwarded argument. Stupidly I had written this > carelessly and had not got the variable names the right way round and hence > was checking if the receiver was forwarded, not the argument. > >> In SqueakJS, I cannot reproduce the issue, i.e., since >> https://github.com/codefrau/SqueakJS/pull/117, #testBecomeForward never >> fails. >> > SqueakJS doesn't use transparent forwarding. You'll also find that it > won't fail in a pre-Spur image. > >> Best, >> >> Christoph >> > _,,,^..^,,,_ > best, Eliot > > -- _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From eliot.miranda at gmail.com Thu Mar 18 19:48:09 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 18 Mar 2021 12:48:09 -0700 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: Hi Liam, On Tue, Mar 16, 2021 at 6:28 AM Liam Proven wrote: > On Tue, 16 Mar 2021 at 09:45, Marcel Taeumel > wrote: > > > > Hi Liam. > > > > > [...] but a couple of the other points seem quite telling... or do > they? > > > > Is this a typical low-effort "You tell me why I should care?"-situation? > :-) > > :-( > > Well, no. I did present a talk advocating Smalltalk as a possible > basis for a next-generation OS just last month and have discussed it > at some length on this ML. But I am not in any way an expert in it. I > tweeted about it, and now Twitter is showing me tweets about > Smalltalk, including this one. > > Honestly, I hoped that some Squeak practitioners here might want to go > and engage themselves, or perhaps even suggest things I could counter > this negativity with. > The major rebuttal is the success stories for Smalltalk. #1 everyone's cell phone (and I mean *everyone's* that isn't a gate array prototype) is built by fab machines controlled using Smalltalk. ControlWORKS is the distributed control system built in Smalltalk built by Texas Instruments, funded by DARPA, in the late '80's. ControlWORKS is now owned by Rudolph, an Austrian company. ControlWORKS is written in VisualWorks Smalltalk. See Lam Research's Smalltalk use. The only kind of machine Lam don't make is lithography. Their machines, or machines built by copying their machines, build everything else. AMD has (had?) their own fab plant, also using ControlWORKS. Essentially all of the world's chips are made in wafer fab machines controlled by Smalltalk. The value of wafers is such (> $1m per wafer) and the physics used so bleeding edge that to achieve down times below 4 hours per year a dynamic language is necessary for in-production maintennance. #2. also VisualWorks, OOCL's ISIS 2 software, a hybrid of Smalltalk and C++ schedules > 60% of world container traffic. Scheduling container traffic is complex. Optimal loading and unloading order decides ship balance, and delivery time. A given container's contents may be bought and sold more than once during shipping, cuz shipping takes several days (eg 4 days China to US). There's some very interesting spicy history with sales of ISIS 2. OOCL sold a copy to COSCO, the Chinese state shipping company. The agreed price involved the governorship of Hong Kong going to a member of OOCL's owning family. #3. JPMorganChase's system of record is a Smalltalk database. Also part of the Kapital system is a futures and derivatives trading "spreadsheet" that allows traders to deal in probability envelopes, which is informed by a simulation of the world's financial markets. All of this is a combination of GemStone and VisualWorks Smalltalk. Kapital paid for the entire $35 m initial development cost in the first 4 days of operation. In the early years of the century I was informed it generated $1.1B annual profits for JPMC. Notably Kapital survived attempts to replace it both with Java and Python competitors on more than two occasions, surviving the merger of JPM & Chase. I'm also informed that the simulation system maxed out gigabit fibre in generating data and caused the meltdown of processors in a datacentre. #4. BMW's parts library, the back end of their CAD system, is a VisualWorks application. #5. Deutsche Bahn's timetable is a VisualWorks app. This is challenging because there are equipment failures and track failures on a daily basis and so the timetable is a live application making rescheduling decisions constantly. and the list goes on; for example several leading insurance companies use Smalltalk. To understand why Smalltalk is used, the key attributes almost all these enterprise-class applications have is rapidly changing domains. For example, JPMC's market simulation has to deal with regulations changing around the globe. Kapital has a 4 day release cycle. Static languages simply can't keep up with the rate of change. > > > Well, if you want to figure out whether your friend is right or wrong, > you could try creating a non-trivial thing in Squeak. This involves getting > to know the entire system, not just the Smalltalk language and standard > library. You would have to figure out how Squeak's tools work and how to > shorten the feedback cycle to the level you are most comfortable with. --- > After that, you are qualified to ponder about what modern Web browsers (+ > DOM/CSS/JavaScript) have achieved yet, and what they still miss. Maybe also > include the motivation behind Docker and containerization in general. > > > > Just kidding. :-) Or am I? > > "Go and see for yourself" is sadly a very common rejoinder when asking > programmers for information about programming languages, but it is > pretty much never a helpful one. :-( > > > -- > Liam Proven – Profile: https://about.me/liamproven > Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com > Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven > UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 > > -- _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From eliot.miranda at gmail.com Thu Mar 18 20:18:19 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 18 Mar 2021 13:18:19 -0700 Subject: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) In-Reply-To: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> References: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> Message-ID: Hi Christoph, very cool work. Let me suggest another avenue for the simulation sandbox. Apologies if we've already discussed this. MethodFinder is a super cool tool, but it has to be prevented from creating havok using a horrible hack. A set of selectors are used to prevent MethodFinder from starting potentially dangerous computations. This list isn't obvious, is never up-to-date, and can potentially exclude useful results. A much better way of implementing MethodFinder seems to be to implement it using simulation and have it maintain the set of objects created so far in the execution, allowing them to be mutated, but aborting whenever an attempt is made to modify an object outside of the sandbox, etc. This could be a much more robust way to architect the message finder, and performance might be adequate. I think it's worth exploring. On Wed, Mar 17, 2021 at 5:32 AM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Hi all! > > > After announcing SimulationStudio and Sandbox yesterday [3], today I'm > happy to introduce you to two other repositories which I have been working > at during the last months. Last week, I had the pleasure to present them > during the German Squeak Winter Demos [4]. Drum roll, say hello to > TelegramBot [1] & TelegramSmalltalkBot [2]! :-) > > > *TelegramBot* is a small framework I built to make it possible to > implement bots for the Telegram messenger [5]. It uses the official > Telegram Bot REST API [6] and maps it to an object-oriented design in > Squeak, providing support for different bot capabilities such as message > sending, receiving, and editing. It also allows sending multi-media message > types such as pictures (Forms), formatted messages (Texts), audio messages > (AbstractSounds), and some others. Last but not least, it comprises a > small API to host your bots in a background process of the image. For more > information, check out the README.md of the repository in [1]. > > > *TelegramSmalltalkBot* is a second repository that implements a Telegram > bot for evaluating Smalltalk expressions by using the TelegramBot framework > from above. Do you know this situation when you wonder "how does XYZ work > in Squeak" and cannot check it out because you do not have any PC or laptop > at hand right now? This situation is history as of today, just send a > message to the bot from wherever you are, just using your phone or even > your watch! In a nutshell, TelegramSmalltalkBot is a simple REPL shell that > utilizes the Squeak Compiler, but it's also packed with a number of > convenient features that make remote access to your image much more > pleasant. For example, the bot does not only answer plain text but also > multi-media messages such as pictures or files depending on the results of > your expressions. You can also use Workspace-like variable bindings or > reply to older messages from the bot to bind the receiver of your message. > For an exhaustive list of all features, visit the repository in [2] or just > send /help to the bot. I also have uploaded a short video demo about it at > [7]. > > > Another important thing to note is that TelegramSmalltalkBot is able to > evaluate every expression in a sandboxed execution environment by using the > SimulationStudio library I announced yesterday [3]. While both projects > have grown rather independently of each other, this usage fills an > important gap for me and I think it is a relevant real-world use case of > the Sandbox. > > > *Please try it out!** :-)* All you need is a Telegram account for free > and a client (Telegram is available cross-platform and can also be used > from the web). I am hosting an instance of the bot myself on my raspberry > pi and I feel confident enough about the isolation quality of my Sandbox > that I dare to unlock public access to the bot for everyone. A small > architecture diagram which I have shown at the Winter Demos is in the > attachments (contains clickable links to the repositories), you can also > find it in the wiki of [2]. > > > Just search in the Telegram app for *@SqueakSmalltalkBot* or follow this > link: https://t.me/SqueakSmalltalkBot [8] (QR code is also in the > attachments) > > > *I'm very much looking forward to your feedback!* If you experience any > problems or have new ideas, please let me know via squeak-dev or GitHub > issues! I'm already planning many new features for the bot - be sure to > watch the repository if you are interested in them. :-) > > > Best, > > Christoph > > > [1] https://github.com/LinqLover/TelegramBot > [2] https://github.com/LinqLover/TelegramSmalltalkBot > [3] > http://forum.world.st/ANN-SimulationStudio-and-sandboxed-execution-for-Squeak-td5127804.html > > [4] > http://forum.world.st/Squeak-Winter-Demos-2021-03-06-3-p-m-6-p-m-CET-virtual-tp5126913.html > [5] https://telegram.org > [6] https://core.telegram.org/bots/api > [7] https://youtu.be/HZCeThLqQmg > [8] https://t.me/SqueakSmalltalkBot > > -- _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From eliot.miranda at gmail.com Thu Mar 18 21:02:48 2021 From: eliot.miranda at gmail.com (Eliot Miranda) Date: Thu, 18 Mar 2021 14:02:48 -0700 Subject: [squeak-dev] [ANN] TelegramBot framework & @SqueakSmalltalkBot :-) In-Reply-To: References: <933d2cd0fac74402a79d811e230043d2@student.hpi.uni-potsdam.de> Message-ID: oops. Ignore me. I just read the longer post about SimulationStudio. Super cool. No need to respond. On Thu, Mar 18, 2021 at 1:18 PM Eliot Miranda wrote: > Hi Christoph, > > very cool work. Let me suggest another avenue for the simulation > sandbox. Apologies if we've already discussed this. MethodFinder is a > super cool tool, but it has to be prevented from creating havok using a > horrible hack. A set of selectors are used to prevent MethodFinder from > starting potentially dangerous computations. This list isn't obvious, is > never up-to-date, and can potentially exclude useful results. A much > better way of implementing MethodFinder seems to be to implement it using > simulation and have it maintain the set of objects created so far in the > execution, allowing them to be mutated, but aborting whenever an attempt is > made to modify an object outside of the sandbox, etc. This could be a much > more robust way to architect the message finder, and performance might be > adequate. I think it's worth exploring. > > On Wed, Mar 17, 2021 at 5:32 AM Thiede, Christoph < > Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > >> Hi all! >> >> >> After announcing SimulationStudio and Sandbox yesterday [3], today I'm >> happy to introduce you to two other repositories which I have been working >> at during the last months. Last week, I had the pleasure to present them >> during the German Squeak Winter Demos [4]. Drum roll, say hello to >> TelegramBot [1] & TelegramSmalltalkBot [2]! :-) >> >> >> *TelegramBot* is a small framework I built to make it possible to >> implement bots for the Telegram messenger [5]. It uses the official >> Telegram Bot REST API [6] and maps it to an object-oriented design in >> Squeak, providing support for different bot capabilities such as message >> sending, receiving, and editing. It also allows sending multi-media message >> types such as pictures (Forms), formatted messages (Texts), audio messages >> (AbstractSounds), and some others. Last but not least, it comprises a >> small API to host your bots in a background process of the image. For more >> information, check out the README.md of the repository in [1]. >> >> >> *TelegramSmalltalkBot* is a second repository that implements a Telegram >> bot for evaluating Smalltalk expressions by using the TelegramBot framework >> from above. Do you know this situation when you wonder "how does XYZ work >> in Squeak" and cannot check it out because you do not have any PC or laptop >> at hand right now? This situation is history as of today, just send a >> message to the bot from wherever you are, just using your phone or even >> your watch! In a nutshell, TelegramSmalltalkBot is a simple REPL shell that >> utilizes the Squeak Compiler, but it's also packed with a number of >> convenient features that make remote access to your image much more >> pleasant. For example, the bot does not only answer plain text but also >> multi-media messages such as pictures or files depending on the results of >> your expressions. You can also use Workspace-like variable bindings or >> reply to older messages from the bot to bind the receiver of your message. >> For an exhaustive list of all features, visit the repository in [2] or just >> send /help to the bot. I also have uploaded a short video demo about it at >> [7]. >> >> >> Another important thing to note is that TelegramSmalltalkBot is able to >> evaluate every expression in a sandboxed execution environment by using the >> SimulationStudio library I announced yesterday [3]. While both projects >> have grown rather independently of each other, this usage fills an >> important gap for me and I think it is a relevant real-world use case of >> the Sandbox. >> >> >> *Please try it out!** :-)* All you need is a Telegram account for free >> and a client (Telegram is available cross-platform and can also be used >> from the web). I am hosting an instance of the bot myself on my raspberry >> pi and I feel confident enough about the isolation quality of my Sandbox >> that I dare to unlock public access to the bot for everyone. A small >> architecture diagram which I have shown at the Winter Demos is in the >> attachments (contains clickable links to the repositories), you can also >> find it in the wiki of [2]. >> >> >> Just search in the Telegram app for *@SqueakSmalltalkBot* or follow this >> link: https://t.me/SqueakSmalltalkBot [8] (QR code is also in the >> attachments) >> >> >> *I'm very much looking forward to your feedback!* If you experience any >> problems or have new ideas, please let me know via squeak-dev or GitHub >> issues! I'm already planning many new features for the bot - be sure to >> watch the repository if you are interested in them. :-) >> >> >> Best, >> >> Christoph >> >> >> [1] https://github.com/LinqLover/TelegramBot >> [2] https://github.com/LinqLover/TelegramSmalltalkBot >> [3] >> http://forum.world.st/ANN-SimulationStudio-and-sandboxed-execution-for-Squeak-td5127804.html >> >> [4] >> http://forum.world.st/Squeak-Winter-Demos-2021-03-06-3-p-m-6-p-m-CET-virtual-tp5126913.html >> [5] https://telegram.org >> [6] https://core.telegram.org/bots/api >> [7] https://youtu.be/HZCeThLqQmg >> [8] https://t.me/SqueakSmalltalkBot >> >> > > -- > _,,,^..^,,,_ > best, Eliot > -- _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From lproven at gmail.com Thu Mar 18 22:07:51 2021 From: lproven at gmail.com (Liam Proven) Date: Thu, 18 Mar 2021 23:07:51 +0100 Subject: [squeak-dev] Twitter Smalltalk discussion that may interest folk here In-Reply-To: References: Message-ID: On Thu, 18 Mar 2021 at 20:48, Eliot Miranda wrote: > > #1 everyone's cell phone (and I mean *everyone's* that isn't a gate array prototype) is built by fab machines controlled using Smalltalk. ControlWORKS is the distributed control system built in Smalltalk built by Texas Instruments, funded by DARPA, in the late '80's. ControlWORKS is now owned by Rudolph, an Austrian company. ControlWORKS is written in VisualWorks Smalltalk. See Lam Research's Smalltalk use. The only kind of machine Lam don't make is lithography. Their machines, or machines built by copying their machines, build everything else. AMD has (had?) their own fab plant, also using ControlWORKS. Essentially all of the world's chips are made in wafer fab machines controlled by Smalltalk. The value of wafers is such (> $1m per wafer) and the physics used so bleeding edge that to achieve down times below 4 hours per year a dynamic language is necessary for in-production maintennance. This I had not heard of. Impressive. > #2. also VisualWorks, OOCL's ISIS 2 software, a hybrid of Smalltalk and C++ schedules > 60% of world container traffic. Scheduling container traffic is complex. Optimal loading and unloading order decides ship balance, and delivery time. A given container's contents may be bought and sold more than once during shipping, cuz shipping takes several days (eg 4 days China to US). There's some very interesting spicy history with sales of ISIS 2. OOCL sold a copy to COSCO, the Chinese state shipping company. The agreed price involved the governorship of Hong Kong going to a member of OOCL's owning family. Ditto... fascinating! > #3. JPMorganChase's system of record is a Smalltalk database. Also part of the Kapital system is a futures and derivatives trading "spreadsheet" that allows traders to deal in probability envelopes, which is informed by a simulation of the world's financial markets. All of this is a combination of GemStone and VisualWorks Smalltalk. Kapital paid for the entire $35 m initial development cost in the first 4 days of operation. In the early years of the century I was informed it generated $1.1B annual profits for JPMC. Notably Kapital survived attempts to replace it both with Java and Python competitors on more than two occasions, surviving the merger of JPM & Chase. I'm also informed that the simulation system maxed out gigabit fibre in generating data and caused the meltdown of processors in a datacentre. My ex-fiancée is or was one of the programmers who built that, and I've probably at least seen a demo of some tiny part of it. So this one, yes, I did know about. Fantastic anecdote, though. > #4. BMW's parts library, the back end of their CAD system, is a VisualWorks application. > > #5. Deutsche Bahn's timetable is a VisualWorks app. This is challenging because there are equipment failures and track failures on a daily basis and so the timetable is a live application making rescheduling decisions constantly. > > and the list goes on; for example several leading insurance companies use Smalltalk. To understand why Smalltalk is used, the key attributes almost all these enterprise-class applications have is rapidly changing domains. For example, JPMC's market simulation has to deal with regulations changing around the globe. Kapital has a 4 day release cycle. Static languages simply can't keep up with the rate of change. Absolutely wonderful stuff. Thank you! -- Liam Proven – Profile: https://about.me/liamproven Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 19 12:35:59 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 19 Mar 2021 12:35:59 +0000 Subject: [squeak-dev] #testBecomeForward fails when simulated in a rush In-Reply-To: References: <5f2b013b71ac40009143e860a3fd7769@student.hpi.uni-potsdam.de> <95ef19eb17b04cc8919c770e957e6672@student.hpi.uni-potsdam.de>, Message-ID: <946b8c6f5ea34123a9825a160adf1c7b@student.hpi.uni-potsdam.de> Thanks for your explanation! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Eliot Miranda Gesendet: Donnerstag, 18. März 2021 20:20:25 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] #testBecomeForward fails when simulated in a rush Hi Christoph, On Tue, Mar 16, 2021 at 3:23 PM Thiede, Christoph > wrote: Hi Eliot, thanks for fixing it! I still don't understand why the bug only occurred during simulation, but glad you were able to find the cause. :-) The normal VM is a JIT VM. That VM has JIT versions of some primitives, and in particular it has JIT versions of the #== and #~~ primitives. These primitives were correct, hiding the bugs in the interpreter versions. The first time the JIT VM sends a particular message (more accurately if it sends a message and the target method is not in the interpreter's method lookup cache) the VM interprets the method. The next time, because the method is in the interpreter's method lookup cache, the method will be JITTED and the machine code will be executed. So the interpreter version of #== and #~~ are only executed once each early in system startup. From then on the JIT version is used. In simulation primitives are evaluated via the tryPrimitive:withArguments: primitive and this primitive always runs the interpreter's version of a primitive. Hence in simulation one is always using the interpreter's primitives and so one sees the bug. Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von Eliot Miranda > Gesendet: Dienstag, 16. März 2021 20:43:41 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] #testBecomeForward fails when simulated in a rush Hi Christoph, On Sun, Mar 14, 2021 at 8:48 AM Thiede, Christoph > wrote: Hi all, it's Sunday afternoon (at least in my timezone :D) and here's an interesting weekend issue for you, maybe even a bug in the VM: p := [ObjectTest new testBecomeForward] newProcess. p runUntil: [:c | c isDead]. In my fresh trunk image, this expression always fails, i.e. a TestFailure is raised from the second assertion in the test, pt3 == pt2. However, when running the test normally, i.e. executing the first block without simulation, the test passes as expected. Also, when I try to debug the simulation, the test passes again. But I even inserted a halt around the (pt3 == pt2) and could see that it actually evaluated to false. And when I change the expression like this, it suddenly passes: p := [ObjectTest new testBecomeForward] newProcess. p runUntil: [:c | Smalltalk garbageCollect. c isDead]. What is this? Does the VM require some kind of memory sweep before the object identity consistency is restored again? To me, this looks pretty suspicious at least. Thank you. You've found a bug in the interpreted version of primitive 110. It read primitiveIdentical "is the receiver/first argument the same object as the (last) argument?. pop argumentCount because this can be used as a mirror primitive." | thisObject otherObject | otherObject := self stackValue: 1. thisObject := self stackTop. ((objectMemory isOopForwarded: otherObject) or: [argumentCount > 1 and: [objectMemory isOopForwarded: thisObject]]) ifTrue: [self primitiveFailFor: PrimErrBadArgument] ifFalse: [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] but this is the wrong way around. It should read primitiveIdentical "is the receiver/first argument the same object as the (last) argument?. pop argumentCount because this can be used as a mirror primitive." | thisObject otherObject | thisObject := self stackValue: 1. otherObject := self stackTop. ((objectMemory isOopForwarded: otherObject) or: [argumentCount > 1 and: [objectMemory isOopForwarded: thisObject]]) ifTrue: [self primitiveFailFor: PrimErrBadArgument] ifFalse: [self pop: argumentCount + 1 thenPushBool: thisObject = otherObject] The invariant on invoking a primitive is that the receiver is unforwarded. This is because it being the receiver of the message, the message send machinery ensures it is not forwarded (if it was, the cached message send logic would fail, and the slow lookup path checks for a forwarded receiver, unforwarding and repeating the send if so). But primitive arguments could be forwarded. So primitiveIdentical must check for a potentially forwarded argument. Stupidly I had written this carelessly and had not got the variable names the right way round and hence was checking if the receiver was forwarded, not the argument. In SqueakJS, I cannot reproduce the issue, i.e., since https://github.com/codefrau/SqueakJS/pull/117, #testBecomeForward never fails. SqueakJS doesn't use transparent forwarding. You'll also find that it won't fail in a pre-Spur image. Best, Christoph _,,,^..^,,,_ best, Eliot -- _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From lists at fniephaus.com Fri Mar 19 13:26:25 2021 From: lists at fniephaus.com (Fabio Niephaus) Date: Fri, 19 Mar 2021 14:26:25 +0100 Subject: [squeak-dev] Squeak-related Talks this Friday In-Reply-To: References: <1614357289-a56b358b68c1860af9c7f67f3774a427@pckswarms.ch> Message-ID: Hi all, The recordings of our talks at the HPI Symposium at SAP are finally online. Sorry for the delay. "Polyglot Programming with TruffleSqueak and GraalVM". https://www.youtube.com/watch?v=9SyOVmAqqLg "Efficient Block based Programming Interfaces". https://www.youtube.com/watch?v=Meouw-MufUQ "Snap! (No Code - No Limit)". https://www.youtube.com/watch?v=XOyXPmcdDcc Tom and I are happy to answer any questions! Cheers, Fabio On Mon, Mar 1, 2021 at 2:13 PM Fabio Niephaus wrote: > > Hi all, > > Yes, the talks were recorded! We'll publish and share them with you > once we have the actual files. > > Best, > Fabio > > On Fri, Feb 26, 2021 at 5:42 PM Liam Proven wrote: > > > > On Fri, 26 Feb 2021 at 17:35, Bruce O'Neel wrote: > > > > > Is it possible that the talks were recorded, and, if so that we can see them? > > > > Whoops. What he said! I only saw the announcement now. :-( > > > > -- > > Liam Proven – Profile: https://about.me/liamproven > > Email: lproven at cix.co.uk – gMail/gTalk/gHangouts: lproven at gmail.com > > Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven > > UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 > > From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 19 14:53:01 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 19 Mar 2021 14:53:01 +0000 Subject: [squeak-dev] [ann] Radial Menu for Squeak Message-ID: <3b78bbc79730498c815fe33294f1160d@student.hpi.uni-potsdam.de> Hi all, today I have only something small for you, not even worth the capital letters in "[ann]". :-) In the last semester, I had the opportunity to build a radial menu implementation for Squeak together with a fellow student in the context of a lecture about User Interfaces Programming. As a small example for the radial menu, we created a simple color chooser application. Nevertheless, our RadialMenuMorph supports the same protocol as MenuMorph and is ToolBuilder-compatible so you can use both of them interchangeably in your image. There is also a preference (#replaceEveryMenuMorph) that allows you to use RadialMenus in the entire image. Additionally, we also built a simple RadialSliderMorph. It might also be worth a notice that I did not found a way to draw the required geometric objects using BitBlt at the first attempt, so I decided to build my own ArcRingMorph class that renders every pixel on the image side by using the midpoint-circle algorithm. Unfortunately, this is very slow and does not support transparency. If I had had some extra time, I would probably have used the Form rule and instead to create an intersection of a polygon and a circle and then have cached the result. Nevertheless, if you are interested in our results, you can take a look at the repository here: https://github.com/LinqLover/ColorContextMenu Screenshots are also attached. Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: screenshot-library[1].png Type: image/png Size: 24662 bytes Desc: screenshot-library[1].png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: screenshot-hue[1].png Type: image/png Size: 39964 bytes Desc: screenshot-hue[1].png URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: screenshot-radial[1].png Type: image/png Size: 22737 bytes Desc: screenshot-radial[1].png URL: From commits at source.squeak.org Fri Mar 19 15:00:57 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 19 Mar 2021 15:00:57 0000 Subject: [squeak-dev] The Inbox: Morphic-ct.1742.mcz Message-ID: A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1742.mcz ==================== Summary ==================== Name: Morphic-ct.1742 Author: ct Time: 19 March 2021, 4:00:48.463632 pm UUID: 136ee067-4ddc-a84e-86da-f3976f21093a Ancestors: Morphic-mt.1741 Proposal: Adds #mouseFocusChange: hook analogously to #keyboardFocusChange:. An examplary use case for this can be found in ColorContextMenu [1, 2]. [1] https://github.com/LinqLover/ColorContextMenu/blob/master/src/ColorContextMenu-Core.package/RadialMenuMorph.class/instance/mouseFocusChange..st [2] http://forum.world.st/ann-Radial-Menu-for-Squeak-td5127916.html =============== Diff against Morphic-mt.1741 =============== Item was changed: ----- Method: HandMorph>>newMouseFocus: (in category 'focus handling') ----- newMouseFocus: aMorphOrNil "Make the given morph the new mouse focus, canceling the previous mouse focus if any. If the argument is nil, the current mouse focus is cancelled." + + | newFocus oldFocus | + oldFocus := self mouseFocus. + newFocus := aMorphOrNil. + + self mouseFocus: newFocus. + + oldFocus == newFocus ifFalse: [ + oldFocus ifNotNil: [:m | m mouseFocusChange: false]. + newFocus ifNotNil: [:m | m mouseFocusChange: true]]. + + ^ newFocus! - self mouseFocus: aMorphOrNil. - ! Item was changed: ----- Method: Morph>>keyboardFocusChange: (in category 'event handling') ----- keyboardFocusChange: aBoolean + "The message is sent to a morph when its keyboard focus changes. The given argument indicates whether the receiver is gaining (true) or losing (false) the focus. Morphs that accept keystrokes should change their appearance in some way when they are the current keyboard focus." - "The message is sent to a morph when its keyboard focus change. The given argument indicates that the receiver is gaining keyboard focus (versus losing) the keyboard focus. Morphs that accept keystrokes should change their appearance in some way when they are the current keyboard focus." self eventHandler ifNotNil: [:h | h keyboardFocusChange: aBoolean fromMorph: self]. + - self indicateKeyboardFocus ifTrue: [self changed].! Item was added: + ----- Method: Morph>>mouseFocusChange: (in category 'event handling') ----- + mouseFocusChange: aBoolean + "The message is sent to a morph when its mouse focus changes. The given argument indicates whether the receiver is gaining (true) or losing (false) the focus."! From christoph.thiede at student.hpi.uni-potsdam.de Fri Mar 19 15:01:56 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Fri, 19 Mar 2021 10:01:56 -0500 (CDT) Subject: [squeak-dev] The Inbox: Morphic-ct.1742.mcz In-Reply-To: References: Message-ID: <1616166116320-0.post@n4.nabble.com> Note that I decided against adding the protocol on EventHandler, too. We can add this if we have a use case for this, can't we? Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Fri Mar 19 22:02:28 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 19 Mar 2021 22:02:28 0000 Subject: [squeak-dev] The Inbox: Collections-ct.932.mcz Message-ID: A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-ct.932.mcz ==================== Summary ==================== Name: Collections-ct.932 Author: ct Time: 19 March 2021, 11:02:25.937058 pm UUID: 557fe993-fe03-4e44-8723-ce0f8d597f9f Ancestors: Collections-dtl.931 Fixes a bug in the fallback version of String>>#replaceFrom:to:with:startingAt:. If the replacement contains integers, they should be converted into Characters. See ByteArray>>#asString. =============== Diff against Collections-dtl.931 =============== Item was changed: ----- Method: String>>replaceFrom:to:with:startingAt: (in category 'private') ----- replaceFrom: start to: stop with: replacement startingAt: repStart "Primitive. This destructively replaces elements from start to stop in the receiver starting at index, repStart, in the collection, replacement. Answer the receiver. Range checks are performed in the primitive only. Optional. See Object documentation whatIsAPrimitive." + | index repOff | + repOff := repStart - start. + index := start - 1. + [(index := index + 1) <= stop] + whileTrue: [self at: index put: (replacement at: repOff + index) asCharacter].! - super replaceFrom: start to: stop with: replacement startingAt: repStart! From commits at source.squeak.org Fri Mar 19 23:33:29 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 19 Mar 2021 23:33:29 0000 Subject: [squeak-dev] The Inbox: Morphic-ct.1743.mcz Message-ID: A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1743.mcz ==================== Summary ==================== Name: Morphic-ct.1743 Author: ct Time: 20 March 2021, 12:33:20.571756 am UUID: e9e2e46a-8dc3-4f42-aa90-ccab90c774c3 Ancestors: Morphic-mt.1741 Proposals: Make selection logic in Editor a little bit more convenient. When returning back to caret from a selection, don't move the caret beyond the prior selection interval on the first arrow key hit. This matches behavior in Chromium/Blink and Microsoft Windows. =============== Diff against Morphic-mt.1741 =============== Item was changed: ----- Method: Editor>>moveCursor:forward:event:specialBlock: (in category 'private') ----- moveCursor: directionBlock forward: forward event: aKeyboardEvent specialBlock: specialBlock "Private - Move cursor. directionBlock is a one argument Block that computes the new Position from a given one. specialBlock is a one argumentBlock that computes the new position from a given one under the alternate semantics. Note that directionBlock always is evaluated first." | indices newPosition shouldSelect | shouldSelect := aKeyboardEvent shiftPressed. indices := self setIndices: shouldSelect forward: forward. + newPosition := indices at: #moving. + (shouldSelect not and: [self hasSelection]) ifFalse: [ + newPosition := directionBlock value: newPosition. + (aKeyboardEvent commandKeyPressed or: [aKeyboardEvent controlKeyPressed]) + ifTrue: [newPosition := specialBlock value: newPosition]]. - newPosition := directionBlock value: (indices at: #moving). - (aKeyboardEvent commandKeyPressed or: [aKeyboardEvent controlKeyPressed]) - ifTrue: [newPosition := specialBlock value: newPosition]. shouldSelect ifTrue: [self selectMark: (indices at: #fixed) point: newPosition - 1] ifFalse: [self selectAt: newPosition]! From christoph.thiede at student.hpi.uni-potsdam.de Fri Mar 19 23:36:40 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Fri, 19 Mar 2021 18:36:40 -0500 (CDT) Subject: [squeak-dev] The Inbox: Morphic-ct.1743.mcz In-Reply-To: References: Message-ID: <1616197000827-0.post@n4.nabble.com> To be precise, Chromium/Blink and Microsoft Windows also truly advance the selection on the first arrow press iff the command/control is pressed. But personally, I think this is rather inconsistent and inconvenient so I aligned this edge case with the regular behavior without specialBlock ... Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From gettimothy at zoho.com Sat Mar 20 14:32:03 2021 From: gettimothy at zoho.com (gettimothy) Date: Sat, 20 Mar 2021 10:32:03 -0400 Subject: [squeak-dev] The major rebuttal is the success stories for Smalltalk. In-Reply-To: References: Message-ID: <178500cddcd.e70842c028541.2743266350694714261@zoho.com> Thank you, Eliot. This was very informative. I have had a "hunch" about Smalltalk in the same way I had a "hunch" in the beginning days of Linux... I am keeping your talking points for future reference, they will come in handy when I have to explain why I am deleted PHP, Java, .NET, etc from my resume's skillset ! cordially, t ---- On Thu, 18 Mar 2021 15:48:09 -0400 Eliot Miranda wrote ---- Hi Liam, On Tue, Mar 16, 2021 at 6:28 AM Liam Proven wrote: On Tue, 16 Mar 2021 at 09:45, Marcel Taeumel wrote: > > Hi Liam. > > > [...] but a couple of the other points seem quite telling... or do they? > > Is this a typical low-effort "You tell me why I should care?"-situation? :-) :-( Well, no. I did present a talk advocating Smalltalk as a possible basis for a next-generation OS just last month and have discussed it at some length on this ML. But I am not in any way an expert in it. I tweeted about it, and now Twitter is showing me tweets about Smalltalk, including this one. Honestly, I hoped that some Squeak practitioners here might want to go and engage themselves, or perhaps even suggest things I could counter this negativity with. The major rebuttal is the success stories for Smalltalk. #1 everyone's cell phone (and I mean *everyone's* that isn't a gate array prototype) is built by fab machines controlled using Smalltalk.  ControlWORKS is the distributed control system built in Smalltalk built by Texas Instruments, funded by DARPA, in the late '80's.  ControlWORKS is now owned by Rudolph, an Austrian company.  ControlWORKS is written in VisualWorks Smalltalk.   See Lam Research's Smalltalk use. The only kind of machine Lam don't make is lithography.  Their machines, or machines built by copying their machines, build everything else.  AMD has (had?) their own fab plant, also using ControlWORKS.  Essentially all of the world's chips are made in wafer fab machines controlled by Smalltalk.  The value of wafers is such (> $1m per wafer) and the physics used so bleeding edge that to achieve down times below 4 hours per year a dynamic language is necessary for in-production maintennance. #2. also VisualWorks, OOCL's ISIS 2 software, a hybrid of Smalltalk and C++ schedules > 60% of world container traffic.  Scheduling container traffic is complex. Optimal loading and unloading order decides ship balance, and delivery time.  A given container's contents may be bought and sold more than once during shipping, cuz shipping takes several days (eg 4 days China to US).  There's some very interesting spicy history with sales of ISIS 2.  OOCL sold a copy to COSCO, the Chinese state shipping company.  The agreed price involved the governorship of Hong Kong going to a member of OOCL's owning family. #3. JPMorganChase's system of record is a Smalltalk database.  Also part of the Kapital system is a futures and derivatives trading "spreadsheet" that allows traders to deal in probability envelopes, which is informed by a simulation of the world's financial markets.  All of this is a combination of GemStone and VisualWorks Smalltalk.  Kapital paid for the entire $35 m initial development cost in the first 4 days of operation.  In the early years of the century I was informed it generated $1.1B annual profits for JPMC.  Notably Kapital survived attempts to replace it both with Java and Python competitors on more than two occasions, surviving the merger of JPM & Chase.  I'm also informed that the simulation system maxed out gigabit fibre in generating data and caused the meltdown of processors in a datacentre. #4. BMW's parts library, the back end of their CAD system, is a VisualWorks application. #5. Deutsche Bahn's timetable is a VisualWorks app.  This is challenging because there are equipment failures and track failures on a daily basis and so the timetable is a live application making rescheduling decisions constantly. and the list goes on; for example several leading insurance companies use Smalltalk.  To understand why Smalltalk is used, the key attributes almost all these enterprise-class applications have is rapidly changing domains.  For example, JPMC's market simulation has to deal with regulations changing around the globe.  Kapital has a 4 day release cycle.  Static languages simply can't keep up with the rate of change. > Well, if you want to figure out whether your friend is right or wrong, you could try creating a non-trivial thing in Squeak. This involves getting to know the entire system, not just the Smalltalk language and standard library. You would have to figure out how Squeak's tools work and how to shorten the feedback cycle to the level you are most comfortable with. --- After that, you are qualified to ponder about what modern Web browsers (+ DOM/CSS/JavaScript) have achieved yet, and what they still miss. Maybe also include the motivation behind Docker and containerization in general. > > Just kidding. :-) Or am I? "Go and see for yourself" is sadly a very common rejoinder when asking programmers for information about programming languages, but it is pretty much never a helpful one. :-( -- Liam Proven – Profile: https://about.me/liamproven Email: mailto:lproven at cix.co.uk – gMail/gTalk/gHangouts: mailto:lproven at gmail.com Twitter/Facebook/LinkedIn/Flickr: lproven – Skype: liamproven UK: +44 7939-087884 – ČR (+ WhatsApp/Telegram/Signal): +420 702 829 053 -- _,,,^..^,,,_ best, Eliot -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Sat Mar 20 18:17:50 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sat, 20 Mar 2021 18:17:50 0000 Subject: [squeak-dev] The Inbox: KernelTests-ct.395.mcz Message-ID: A new version of KernelTests was added to project The Inbox: http://source.squeak.org/inbox/KernelTests-ct.395.mcz ==================== Summary ==================== Name: KernelTests-ct.395 Author: ct Time: 20 March 2021, 7:17:49.390742 pm UUID: 76e4d450-32dd-d24c-8aad-68ad212ec955 Ancestors: KernelTests-mt.394, KernelTests-ct.375 Tests simulation of #perform:... primitives 83, 84, and 100. Complements Kernel-ct.1367. Reuploaded to add another fixture for the mirror primitive variant of primitive 100. Corrected order of assertion arguments. Replaces KernelTests-ct.38{2,3}, which can be moved into the treated inbox. Depends indeed not only on KernelTests-mt.394 but also on KernelTests-ct.375, it would be nice if we could get the latter merged soon, this has already been causing too many merge conflicts in the past. :-) =============== Diff against KernelTests-mt.394 =============== Item was changed: SystemOrganization addCategory: #'KernelTests-Classes'! SystemOrganization addCategory: #'KernelTests-Methods'! SystemOrganization addCategory: #'KernelTests-Numbers'! SystemOrganization addCategory: #'KernelTests-Objects'! SystemOrganization addCategory: #'KernelTests-Processes'! - SystemOrganization addCategory: #'KernelTests-WriteBarrier'! - SystemOrganization addCategory: #'KernelTests-Models'! Item was changed: ----- Method: AllocationTest>>testOutOfMemorySignal (in category 'tests') ----- testOutOfMemorySignal + "Ensure that OutOfMemory is signaled eventually" - "Ensure that OutOfMemory is signaled eventually. Restrain the available memory first to not stress the machine too much." - | sz | self setFreeSpaceLimitOf: 1024 * 1024 * 1024 * (Smalltalk wordSize = 8 ifTrue: [4] ifFalse: [1.5]) around: [sz := 512*1024*1024. "work around the 1GB alloc bug" + self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory]. + + "Call me when this test fails, I want your machine." + "Current (2017) Spur VMs fail new: & basicNew: with #'bad argument' if given other than a non-negative SmallInteger." + sz := 1024*1024*1024*1024. + self should: [Array new: sz] + raise: OutOfMemory, Error + withExceptionDo: + [:ex| + ex class == Error ifTrue: + [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! - self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory].! Item was removed: - ----- Method: AllocationTest>>testOutOfMemorySignalExtreme (in category 'tests') ----- - testOutOfMemorySignalExtreme - "Try to allocate a ridiculous amount of memory and check whether the expected error is signaled. Call Eliot when this test fails, he want your machine. :-) - - Note that current (2017) Spur VMs fail in #new: and #basicNew: with #'bad argument' if given other than a non-negative SmallInteger. - - Also note that this test can be quite stressful to your machine depending on how your operating system allocates the required memory behind the curtains. Better not triggering some robot fetching a tape from somewhere..." - - | sz | - sz := 1024*1024*1024*1024. "= 1 TiB" - self should: [Array new: sz] - raise: OutOfMemory, Error - withExceptionDo: - [:ex| - ex class == Error ifTrue: - [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! Item was removed: - ----- Method: BlockClosureTest>>return: (in category 'private') ----- - return: something - - ^ something! Item was removed: - ----- Method: BlockClosureTest>>testMoreThanOnce (in category 'tests - evaluating') ----- - testMoreThanOnce - "Make sure that we can use once more than once" - | moreThanOnce | - moreThanOnce := (1 to: 3) collect: [:e | [String new] once -> [Array new] once]. - self assert: (moreThanOnce allSatisfy: [:each | each key isString]). - self assert: (moreThanOnce allSatisfy: [:each | each value isArray]). - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]).! Item was removed: - ----- Method: BlockClosureTest>>testMoreThanOnceForEqualBlocks (in category 'tests - evaluating') ----- - testMoreThanOnceForEqualBlocks - "Make sure that we can use once more than once" - | moreThanOnce | - moreThanOnce := (1 to: 3) collect: [:e | [Object new] once -> [Object new] once]. - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]). - self assert: (moreThanOnce noneSatisfy: [:each | each key == each value]).! Item was changed: ----- Method: BlockClosureTest>>testRunSimulated (in category 'tests') ----- testRunSimulated + self assert: Rectangle equals: (Context runSimulated: aBlockClosure asContext) class! - self assert: Rectangle equals: - (Context runSimulated: aBlockClosure asContext) class. - self assert: 42 equals: - (Context runSimulated: [self return: 42]). - self - should: [Context runSimulated: [self halt]] - raise: Halt.! Item was removed: - ----- Method: BlockClosureTest>>testRunSimulatedContextAtEachStep (in category 'tests') ----- - testRunSimulatedContextAtEachStep - - | context | - context := aBlockClosure asContext. - self assert: Rectangle equals: (thisContext - runSimulated: context - contextAtEachStep: [:ctxt | self assert: - [ctxt == context or: [ctxt hasSender: context]]]) class.! Item was changed: ----- Method: BlockClosureTest>>testSetUp (in category 'tests') ----- testSetUp "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" self deny: aBlockClosure isContext. self assert: aBlockClosure isClosure. self assert: aBlockClosure home = homeOfABlockClosure. self assert: aBlockClosure receiver = self. + self assert: aBlockClosure method isCompiledMethod! - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) - ifTrue: [aBlockClosure method isCompiledBlock] - ifFalse: [aBlockClosure method isCompiledMethod])! Item was changed: ----- Method: BlockClosureTest>>testTallyInstructions (in category 'tests') ----- testTallyInstructions + self assert: (Context tallyInstructions: aBlockClosure asContext) size = 15! - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) - ifTrue: [14] - ifFalse: [15]) - equals: (Context tallyInstructions: aBlockClosure asContext) size! Item was changed: ----- Method: ClassTest>>testChangeClassOf (in category 'tests') ----- testChangeClassOf "Exercise primitiveChangeClass (primitive 115) for a common use case. This should pass for any Squeak image format (but failed for image format 68002 prior to VM fix)" + self shouldnt: [Inspector new primitiveChangeClassTo: CompiledMethodInspector new] raise: Error! - self shouldnt: [Exception new primitiveChangeClassTo: Error new] raise: Error! Item was changed: ----- Method: CompiledMethodTest>>testClosureSize (in category 'tests - closures') ----- testClosureSize + self + assert: ((self class >> #withClosure) embeddedBlockClosures at: 1) size + equals: 2; + assert: ((self class >> #withClosureNoNLR) embeddedBlockClosures at: 1) size + equals: 2! - | compiledMethod expectedSize | - compiledMethod := (self class >> #withClosure). - expectedSize := compiledMethod bytecodeSetName - caseOf: { - ['SistaV1'] -> [3]. - ['V3PlusClosures'] -> [2]}. - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size. - compiledMethod := (self class >> #withClosureNoNLR). - expectedSize := compiledMethod bytecodeSetName - caseOf: { - ['SistaV1'] -> [3]. - ['V3PlusClosures'] -> [2]}. - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size.! Item was added: + TestCase subclass: #ContextTest + instanceVariableNames: 'aCompiledMethod aReceiver aSender aContext' + classVariableNames: '' + poolDictionaries: '' + category: 'KernelTests-Methods'! + + !ContextTest commentStamp: 'ct 1/27/2020 13:03' prior: 0! + I am an SUnit Test of Context. See also BlockClosureTest. + See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak see http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ and http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) + My fixtures are: + aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" + aSender - just some arbitrary object, thisContext + aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". + aContext - just some arbitray context ... + + ! Item was added: + ----- Method: ContextTest>>privRestartTest (in category 'private') ----- + privRestartTest + "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" + |a firstTimeThrough | + firstTimeThrough := true. + a := 10. + + self assert: 30 equals: [|b| + self assert: 10 = a . + self assert: nil == b. + b := a + 20. + firstTimeThrough ifTrue: [ + firstTimeThrough := false. + thisContext restart.]. + b] value + ! Item was added: + ----- Method: ContextTest>>setUp (in category 'running') ----- + setUp + super setUp. + aCompiledMethod := Rectangle methodDict at: #rightCenter. + aReceiver := 100 at 100 corner: 200 at 200. + aSender := thisContext. + aContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! Item was added: + ----- Method: ContextTest>>testActivateReturnValue (in category 'tests') ----- + testActivateReturnValue + self assert: (aSender activateReturn: aContext value: #()) isContext. + self assert: ((aSender activateReturn: aContext value: #()) receiver = aContext).! Item was added: + ----- Method: ContextTest>>testCopyStack (in category 'tests') ----- + testCopyStack + self assert: aContext copyStack printString = aContext printString.! Item was added: + ----- Method: ContextTest>>testFindContextSuchThat (in category 'tests') ----- + testFindContextSuchThat + self assert: (aContext findContextSuchThat: [:each| true]) printString = aContext printString. + self assert: (aContext hasContext: aContext). ! Item was added: + ----- Method: ContextTest>>testMethodContext (in category 'tests') ----- + testMethodContext + self assert: aContext home notNil. + self assert: aContext receiver notNil. + self assert: aContext method isCompiledMethod.! Item was added: + ----- Method: ContextTest>>testMethodIsBottomContext (in category 'tests') ----- + testMethodIsBottomContext + self assert: aContext bottomContext = aSender. + self assert: aContext secondFromBottom = aContext.! Item was added: + ----- Method: ContextTest>>testPrimitive100 (in category 'tests') ----- + testPrimitive100 + + { + {#isNil. {}. Object}. "valid 0-arg message" + {#=. {true}. UndefinedObject}. "valid unary message" + {#ifNil:ifNotNil:. {[2]. [:x | x]}. Object}. "valid binary message" + {{}. #=. {true}. SequenceableCollection}. "mirror primitive" + {#isNil}. "missing arguments" + {#isNil. 'not an array'}. "invalid arguments" + {#isNil. {}}. "missing lookupClass" + {#isNil. {'excess arg'}. Object}. "too many arguments" + {#=. {}. UndefinedObject}. "missing argument" + {#isNil. {}. Boolean}. "lookupClass not in inheritance chain" + } do: [:args | + self + assert: (nil tryPrimitive: 100 withArgs: args) + equals: (Context runSimulated: [nil tryPrimitive: 100 withArgs: args])].! Item was added: + ----- Method: ContextTest>>testPrimitive83 (in category 'tests') ----- + testPrimitive83 + + { + {#isNil}. "valid 0-arg message" + {#=. true}. "valid unary message" + {#ifNil:ifNotNil:. [2]. [:x | x]}. "valid binary message" + {#isNil. 'excess arg'}. "too many arguments" + {#=}. "missing argument" + } do: [:args | + self + assert: (nil tryPrimitive: 83 withArgs: args) + equals: (Context runSimulated: [nil tryPrimitive: 83 withArgs: args])].! Item was added: + ----- Method: ContextTest>>testPrimitive84 (in category 'tests') ----- + testPrimitive84 + + { + {#isNil. {}}. "valid 0-arg message" + {#=. {true}}. "valid unary message" + {#ifNil:ifNotNil:. {[2]. [:x | x]}}. "valid binary message" + {#isNil}. "missing arguments" + {#isNil. 'not an array'}. "invalid arguments" + {#isNil. {'excess arg'}}. "too many arguments" + {#=. {}}. "missing argument" + } do: [:args | + self + assert: (nil tryPrimitive: 84 withArgs: args) + equals: (Context runSimulated: [nil tryPrimitive: 84 withArgs: args])].! Item was added: + ----- Method: ContextTest>>testRestart (in category 'tests') ----- + testRestart + self should: [self privRestartTest] notTakeMoreThan: 0.1 second! Item was added: + ----- Method: ContextTest>>testReturn (in category 'tests') ----- + testReturn + "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." + aContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). + self assert: (aContext return: 5) = 5! Item was added: + ----- Method: ContextTest>>testSetUp (in category 'tests') ----- + testSetUp + "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" + self assert: aContext isContext. + self deny: aContext isExecutingBlock. + self deny: aContext isClosure. + self deny: aContext isDead. + "self assert: aMethodContext home = aReceiver." + "self assert: aMethodContext blockHome = aReceiver." + self assert: aContext receiver = aReceiver. + self assert: aContext method isCompiledMethod. + self assert: aContext method = aCompiledMethod. + self assert: aContext methodNode selector = #rightCenter. + self assert: (aContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. + self assert: aContext client printString = 'ContextTest>>#testSetUp'. + ! Item was removed: - ----- Method: FloatTest class>>testClassConstantsPasses (in category 'utilities') ----- - testClassConstantsPasses - "Answer if testClassConstants passes. This can be used in e.g. the Kernel Package prolog - to test if Float initialize needs to be run." - [self new testClassConstants] - on: TestResult failure - do: [:ex| ^false]. - ^true! Item was removed: - ----- Method: FloatTest>>assert:equals:withinUlp: (in category 'asserting') ----- - assert: expected equals: actual withinUlp: maxUlp - self assert: (expected - actual) abs <= (maxUlp * expected asFloat ulp)! Item was removed: - ----- Method: FloatTest>>floatLiteralsIn: (in category 'private') ----- - floatLiteralsIn: method - | floatLiterals | - floatLiterals := OrderedCollection new. - method allLiteralsDo: - [:lit| lit isFloat ifTrue: [floatLiterals addLast: lit]]. - ^floatLiterals! Item was removed: - ----- Method: FloatTest>>methodContainsFloatLiteral: (in category 'private') ----- - methodContainsFloatLiteral: method - method isQuick ifFalse: - [method allLiteralsDo: - [:lit| lit isFloat ifTrue: [^true]]]. - ^false! Item was removed: - ----- Method: FloatTest>>methodsMaybeContainingBrokenCompiledConstants (in category 'private') ----- - methodsMaybeContainingBrokenCompiledConstants - "Answer a set of all methods in the system which contain float constants that differ from those obtaiuned by - recompiling. These may indicate an old compiler issue, or indeed an issue with the current compiler. This is a - variant of testCompiledConstants used for collecting the set of methods rather than testing that none exist." - | identifiedPatients | - identifiedPatients := IdentitySet new. - CurrentReadOnlySourceFiles cacheDuring: - [self systemNavigation allSelectorsAndMethodsDo: - [:class :selector :method| - (self methodContainsFloatLiteral: method) ifTrue: - [| newMethodAndNode newLiterals oldLiterals | - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. - newLiterals := self floatLiteralsIn: newMethodAndNode method. - oldLiterals := self floatLiteralsIn: method. - "Convenience doit for recompiling broken methods:..." - "class recompile: selector" - newLiterals size = oldLiterals size - ifFalse: [identifiedPatients add: method] - ifTrue: - [newLiterals with: oldLiterals do: - [:new :old| - (new asIEEE64BitWord = old asIEEE64BitWord - or: [new isNaN and: old isNaN]) ifFalse: - [identifiedPatients add: method]]]]]]. - ^identifiedPatients! Item was removed: - ----- Method: FloatTest>>testClassConstants (in category 'tests - characterization') ----- - testClassConstants - - "Test all the class constants that are floats to check that they are valid. - Sometimes compiler bugs mean that the initialization method is incorrect, etc" - | expectedVariables unexpectedVariables "these two are for determining if this test is correct, not its results" - finiteVariables infiniteVariables nanVariables | - finiteVariables := #(Pi Halfpi Twopi ThreePi RadiansPerDegree Ln2 Ln10 Sqrt2 E Epsilon MaxVal MaxValLn NegativeZero). - infiniteVariables := #(Infinity NegativeInfinity). - nanVariables := #(NaN). - expectedVariables := Set new. - unexpectedVariables := Set new. - Float classPool keysAndValuesDo: - [:name :value| - value isFloat - ifTrue: - [(finiteVariables includes: name) ifTrue: - [expectedVariables add: name. - self assert: value isFinite. - self deny: value isInfinite. - self deny: value isNaN]. - (infiniteVariables includes: name) ifTrue: - [expectedVariables add: name. - self deny: value isFinite. - self assert: value isInfinite. - self deny: value isNaN]. - (nanVariables includes: name) ifTrue: - [expectedVariables add: name. - self deny: value isFinite. - self deny: value isInfinite. - self assert: value isNaN]. - (expectedVariables includes: name) ifFalse: - [unexpectedVariables add: name]] - ifFalse: - [self deny: ((finiteVariables includes: name) or: [(infiniteVariables includes: name) or: [nanVariables includes: name]])]]. - "Now check that test itself is working as intended..." - self assert: unexpectedVariables isEmpty. - self assert: expectedVariables = (finiteVariables, infiniteVariables, nanVariables) asSet! Item was removed: - ----- Method: FloatTest>>testCloseToFurthestCloseToNeasrest (in category 'tests - compare') ----- - testCloseToFurthestCloseToNeasrest - | x nearest furthest | - x := 1.0e-6. - nearest := 1.0e-7. - furthest := 0.0. - self assert: (x - nearest) abs < (x - furthest) abs. - self assert: (x closeTo: furthest) ==> (x closeTo: nearest)! Item was removed: - ----- Method: FloatTest>>testCloseToIsSymmetric (in category 'tests - compare') ----- - testCloseToIsSymmetric - self assert: ((1<<2000) reciprocal closeTo: 1.0e-6) equals: (1.0e-6 closeTo: (1<<2000) reciprocal)! Item was removed: - ----- Method: FloatTest>>testCompiledConstants (in category 'tests') ----- - testCompiledConstants - "Test that any methods containing a floating point literal have been correctly compiled." - CurrentReadOnlySourceFiles cacheDuring: - [self systemNavigation allSelectorsAndMethodsDo: - [:class :selector :method| - (self methodContainsFloatLiteral: method) ifTrue: - [| newMethodAndNode newLiterals oldLiterals | - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. - newLiterals := self floatLiteralsIn: newMethodAndNode method. - oldLiterals := self floatLiteralsIn: method. - "Convenience doit for recompiling broken methods:..." - "class recompile: selector" - self assert: newLiterals size = oldLiterals size. - newLiterals with: oldLiterals do: - [:new :old| - self assert: (new asIEEE64BitWord = old asIEEE64BitWord - or: [new isNaN and: old isNaN])]]]]! Item was removed: - ----- Method: FloatTest>>testLog2near1 (in category 'tests - mathematical functions') ----- - testLog2near1 - self assert: 1.0 predecessor ln / 2 ln equals: 1.0 predecessor log2 withinUlp: 2. - self assert: 1.0 successor ln / 2 ln equals: 1.0 successor log2 withinUlp: 2! Item was removed: - TestCase subclass: #MethodContextTest - instanceVariableNames: 'aCompiledMethod aReceiver aMethodContext aSender' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-Methods'! - - !MethodContextTest commentStamp: 'eem 3/30/2017 17:42' prior: 0! - I am an SUnit Test of Context. See also BlockClosureTest. - See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak see http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ and http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) - My fixtures are: - aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" - aSender - just some arbitrary object, thisContext - aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". - aMethodContext - just some arbitray context ... - - ! Item was removed: - ----- Method: MethodContextTest>>privRestartTest (in category 'private') ----- - privRestartTest - "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" - |a firstTimeThrough | - firstTimeThrough := true. - a := 10. - - self assert: 30 equals: [|b| - self assert: 10 = a . - self assert: nil == b. - b := a + 20. - firstTimeThrough ifTrue: [ - firstTimeThrough := false. - thisContext restart.]. - b] value - ! Item was removed: - ----- Method: MethodContextTest>>setUp (in category 'running') ----- - setUp - super setUp. - aCompiledMethod := Rectangle methodDict at: #rightCenter. - aReceiver := 100 at 100 corner: 200 at 200. - aSender := thisContext. - aMethodContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! Item was removed: - ----- Method: MethodContextTest>>testActivateReturnValue (in category 'tests') ----- - testActivateReturnValue - self assert: (aSender activateReturn: aMethodContext value: #()) isContext. - self assert: ((aSender activateReturn: aMethodContext value: #()) receiver = aMethodContext).! Item was removed: - ----- Method: MethodContextTest>>testCopyStack (in category 'tests') ----- - testCopyStack - self assert: aMethodContext copyStack printString = aMethodContext printString.! Item was removed: - ----- Method: MethodContextTest>>testCopyTo (in category 'tests') ----- - testCopyTo - - | context depth targetSender | - context := thisContext. - depth := 1. - targetSender := context. - [ (targetSender := targetSender sender) isNil ] whileFalse: [ - | original copy | - original := context. - copy := context copyTo: targetSender. - 1 to: depth do: [ :index | - index = 1 ifFalse: [ - "Since we're copying thisContext, the pc and stackPtr may be different for the current frame." - self - assert: original pc equals: copy pc; - assert: original stackPtr equals: copy stackPtr ]. - self - deny: original == copy; - assert: original method equals: copy method; - assert: original closure equals: copy closure; - assert: original receiver equals: copy receiver. - original := original sender. - copy := copy sender ]. - self - assert: copy isNil; - assert: original == targetSender. - depth := depth + 1 ]! Item was removed: - ----- Method: MethodContextTest>>testFindContextSuchThat (in category 'tests') ----- - testFindContextSuchThat - self assert: (aMethodContext findContextSuchThat: [:each| true]) printString = aMethodContext printString. - self assert: (aMethodContext hasContext: aMethodContext). ! Item was removed: - ----- Method: MethodContextTest>>testMethodContext (in category 'tests') ----- - testMethodContext - self assert: aMethodContext home notNil. - self assert: aMethodContext receiver notNil. - self assert: aMethodContext method isCompiledMethod.! Item was removed: - ----- Method: MethodContextTest>>testMethodIsBottomContext (in category 'tests') ----- - testMethodIsBottomContext - self assert: aMethodContext bottomContext = aSender. - self assert: aMethodContext secondFromBottom = aMethodContext.! Item was removed: - ----- Method: MethodContextTest>>testRestart (in category 'tests') ----- - testRestart - self should: [self privRestartTest] notTakeMoreThan: 0.1 second! Item was removed: - ----- Method: MethodContextTest>>testReturn (in category 'tests') ----- - testReturn - "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." - aMethodContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). - self assert: (aMethodContext return: 5) = 5! Item was removed: - ----- Method: MethodContextTest>>testSetUp (in category 'tests') ----- - testSetUp - "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" - self assert: aMethodContext isContext. - self deny: aMethodContext isExecutingBlock. - self deny: aMethodContext isClosure. - self deny: aMethodContext isDead. - "self assert: aMethodContext home = aReceiver." - "self assert: aMethodContext blockHome = aReceiver." - self assert: aMethodContext receiver = aReceiver. - self assert: aMethodContext method isCompiledMethod. - self assert: aMethodContext method = aCompiledMethod. - self assert: aMethodContext methodNode selector = #rightCenter. - self assert: (aMethodContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. - self assert: aMethodContext client printString = 'MethodContextTest>>#testSetUp'. - ! Item was removed: - TestCase subclass: #ModelTest - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-Models'! Item was removed: - ----- Method: ModelTest>>testCopyDependents (in category 'tests') ----- - testCopyDependents - - | bar foo | - foo := Model new. - foo addDependent: 42. - self assert: {42} equals: foo dependents asArray. - - bar := foo copy. - self assert: bar dependents isEmpty.! Item was removed: - ----- Method: NumberTest>>testExactLog2 (in category 'tests') ----- - testExactLog2 - -10 to: 10 do: [:i | self assert: i equals: (2 raisedToInteger: i) log2]. - Float emin - Float precision + 1 to: Float emax do: [:i | self assert: i equals: (1.0 timesTwoPower: i) log2].! Item was removed: - ----- Method: NumberTest>>testLog2doesNotOverflow (in category 'tests') ----- - testLog2doesNotOverflow - "Note: though this is not a strict identity, we can use strict Float equality here" - self assert: 3000.0 equals: ((1 bitShift: 3000) - 1) log2. - self assert: 1500.0 equals: (((1 bitShift: 3000) - 1) / (1 bitShift: 1500)) log2.! Item was removed: - ----- Method: NumberTest>>testLog2doesNotUnderflow (in category 'tests') ----- - testLog2doesNotUnderflow - "Note: though this is not a strict identity, we can use strict Float equality here" - self assert: -2000.0 equals: ((1 bitShift: 2000) - 1) reciprocal log2! Item was removed: - ----- Method: ObjectTest>>testCopyDependents (in category 'tests') ----- - testCopyDependents - - | bar foo | - foo := Object new. - foo addDependent: 42. - self assert: {42} equals: foo dependents asArray. - - bar := foo copy. - self assert: bar dependents isEmpty.! Item was removed: - ----- Method: ProcessTest>>genuineProcess (in category 'support') ----- - genuineProcess - - "Usually, we don't want to expose this from the class under test." - ^ Processor instVarNamed: 'genuineProcess'! Item was removed: - ----- Method: ProcessTest>>testEvaluateOnBehalfOf (in category 'tests') ----- - testEvaluateOnBehalfOf - - | p1 p2 sem results | - self genuineProcess == Processor activeProcess - ifFalse: [self fail: 'Cannot debug this test']. - - sem := Semaphore new. - p1 := [] newProcess. - p1 environmentAt: #foo put: 1. - p2 := [ - Processor activeProcess environmentAt: #foo put: 2. - results := { - Processor activeProcess environmentAt: #foo. - self genuineProcess environmentAt: #foo. - Processor activeProcess - evaluate: [Processor activeProcess environmentAt: #foo] - onBehalfOf: p1. - Processor activeProcess - evaluate: [self genuineProcess environmentAt: #foo] - onBehalfOf: p1. - Processor activeProcess environmentAt: #foo }. - sem signal - ] newProcess. - - p2 resume. - sem wait. - - self assert: {2. 2. 1. 2. 2} equals: results.! Item was removed: - ----- Method: ProcessTest>>testProcessFaithfulRunning (in category 'tests') ----- - testProcessFaithfulRunning - "While simulating a process using #runUntilErrorOrReturnFrom:, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." - - | process result | - process := Process forBlock: [ - result := Processor activeProcess environmentAt: #foo]. - process environmentAt: #foo put: 42. - - process complete: process suspendedContext. - - self assert: 42 equals: result.! Item was removed: - ----- Method: ProcessTest>>testProcessFaithfulSimulation (in category 'tests') ----- - testProcessFaithfulSimulation - "While simulating a process using the bytecode simulation machinery, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." - - | process result | - process := Process forBlock: [ - result := Processor activeProcess environmentAt: #foo]. - process environmentAt: #foo put: 42. - - process runUntil: [:context | context isDead]. - - self assert: 42 equals: result.! Item was removed: - ----- Method: PromiseTest>>testAnErrorInOnRejectedRejectsPromise (in category 'tests - monad') ----- - testAnErrorInOnRejectedRejectsPromise - "https://promisesaplus.com section 2.2.7.2" - | p q error | - p := Promise new. - q := p ifRejected: [:e | (error := KeyNotFound new) signal]. - p rejectWith: 1. - self assert: p isRejected description: 'Original Promise not rejected'. - self assert: q isRejected description: 'Broken Promise not rejected'. - self assert: p error = 1. - self assert: q error == error.! Item was changed: ----- Method: PromiseTest>>testAnErrorInThenRejectsPromise (in category 'tests - monad') ----- testAnErrorInThenRejectsPromise + | p q | - "https://promisesaplus.com section 2.2.7.2" - | p q error | p := Promise new. + q := p then: [:v | KeyNotFound signal]. - q := p then: [:v | (error := KeyNotFound new) signal]. p resolveWith: 1. self deny: p isRejected description: 'Original Promise rejected'. + self assert: q isRejected description: 'Broken Promise not rejected'.! - self assert: q isRejected description: 'Broken Promise not rejected'. - self assert: p value = 1. - self assert: q error == error.! Item was removed: - ----- Method: PromiseTest>>testNilErrBlockPropagation (in category 'tests - monad') ----- - testNilErrBlockPropagation - "https://promisesaplus.com section 2.2.7.4" - | p q | - p := Promise new. - q := p then: [:v | self error: 'Shouldn''t call resolvedBlock'] ifRejected: nil. - p rejectWith: 1. - self assert: p isRejected. - self assert: q isRejected. - self assert: p error equals: 1. - self assert: q error equals: 1.! Item was removed: - ----- Method: PromiseTest>>testNilResolvedBlockPropagation (in category 'tests - monad') ----- - testNilResolvedBlockPropagation - "https://promisesaplus.com section 2.2.7.3" - | p q | - p := Promise new. - q := p then: nil ifRejected: [:e | self error: 'Shouldn''t call errBlock']. - p resolveWith: 1. - self assert: p isResolved. - self assert: q isResolved. - self assert: p value equals: 1. - self assert: q value equals: 1.! Item was changed: ----- Method: PromiseTest>>testifRejectedRunsBlockIfPromiseFails (in category 'tests - monad') ----- testifRejectedRunsBlockIfPromiseFails - "https://promisesaplus.com section 2.2.7.1" | p q error | error := nil. p := Promise new. + q := p ifRejected: [:e | error := e]. - q := p ifRejected: [:e | error := e "N.B. returns a value, does not signal an Exception"]. p rejectWith: KeyNotFound new. + self assert: q isRejected. + self assert: KeyNotFound equals: error class.! - self assert: q isResolved. - self assert: KeyNotFound equals: error class. - self assert: q value == error.! Item was removed: - Object subclass: #WriteBarrierAnotherStub - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-WriteBarrier'! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var1 (in category 'accessing') ----- - var1 - ^ var1! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var10 (in category 'accessing') ----- - var10 - ^ var10! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var10: (in category 'accessing') ----- - var10: anObject - var10 := anObject! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var1: (in category 'accessing') ----- - var1: anObject - var1 := anObject! Item was removed: - Object subclass: #WriteBarrierStub - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-WriteBarrier'! Item was removed: - ----- Method: WriteBarrierStub>>var1 (in category 'accessing') ----- - var1 - ^ var1! Item was removed: - ----- Method: WriteBarrierStub>>var10 (in category 'accessing') ----- - var10 - ^ var10! Item was removed: - ----- Method: WriteBarrierStub>>var10: (in category 'accessing') ----- - var10: anObject - var10 := anObject! Item was removed: - ----- Method: WriteBarrierStub>>var1: (in category 'accessing') ----- - var1: anObject - var1 := anObject! Item was removed: - TestCase subclass: #WriteBarrierTest - instanceVariableNames: '' - classVariableNames: 'ContextInstance' - poolDictionaries: '' - category: 'KernelTests-WriteBarrier'! - - !WriteBarrierTest commentStamp: '' prior: 0! - My tests ensure the ReadOnly property of objects work properly. - - #testMutateIVObject is a good start to understand what is going on. - - The VM needs to be compiled with -DIMMUTABILTY= true for those tests to work.! Item was removed: - ----- Method: WriteBarrierTest class>>initialize (in category 'initialization') ----- - initialize - - ContextInstance := Context sender: nil receiver: self new method: self >> #alwaysWritableObjects arguments: #()! Item was removed: - ----- Method: WriteBarrierTest>>alwaysReadOnlyObjects (in category 'guinea pigs') ----- - alwaysReadOnlyObjects - "Immediates are always immutable" - ^ { 1 }! Item was removed: - ----- Method: WriteBarrierTest>>alwaysWritableObjects (in category 'guinea pigs') ----- - alwaysWritableObjects - "Objects that currently can't be immutable" - ^ { ContextInstance . - Processor . - Processor activeProcess }! Item was removed: - ----- Method: WriteBarrierTest>>expectedFailures (in category 'expected failures') ----- - expectedFailures - Smalltalk supportsReadOnlyObjects ifFalse: - [^self class testSelectors]. - ^#( testMutateByteArrayUsingDoubleAtPut testMutateByteArrayUsingFloatAtPut ), - ((Smalltalk classNamed: #MirrorPrimitives) - ifNil: [#(testBasicProxyReadOnly testBasicProxyWritable testSetIsReadOnlySuccessProxy)] - ifNotNil: [#()])! Item was removed: - ----- Method: WriteBarrierTest>>maybeReadOnlyObjects (in category 'guinea pigs') ----- - maybeReadOnlyObjects - "ByteObject, Variable object, fixed sized object" - ^ { { 1 . 2 . 3 } asByteArray . { 1 . 2 . 3 } . (MessageSend receiver: 1 selector: #+ argument: 2) }! Item was removed: - ----- Method: WriteBarrierTest>>testAttemptToMutateLiterals (in category 'tests - object') ----- - testAttemptToMutateLiterals - | guineaPigs | - guineaPigs := {#[1 2 3] . #(1 2 3) }. - guineaPigs do: - [ :guineaPig | - self should: [guineaPig at: 1 put: 4] - raise: ModificationForbidden]. - - self should: [guineaPigs first become: guineaPigs second ] - raise: ModificationForbidden. - - self should: [ByteString adoptInstance: guineaPigs first] - raise: ModificationForbidden. - - self should: [WeakArray adoptInstance: guineaPigs last] - raise: ModificationForbidden! Item was removed: - ----- Method: WriteBarrierTest>>testBasicProxyReadOnly (in category 'tests - proxy') ----- - testBasicProxyReadOnly - self alwaysReadOnlyObjects do: [ :each | - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: true ]! Item was removed: - ----- Method: WriteBarrierTest>>testBasicProxyWritable (in category 'tests - proxy') ----- - testBasicProxyWritable - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: false ]! Item was removed: - ----- Method: WriteBarrierTest>>testBasicReadOnly (in category 'tests - object') ----- - testBasicReadOnly - self alwaysReadOnlyObjects do: [ :each | - self assert: each isReadOnlyObject equals: true ]! Item was removed: - ----- Method: WriteBarrierTest>>testBasicWritable (in category 'tests - object') ----- - testBasicWritable - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | - self assert: each isReadOnlyObject equals: false ]! Item was removed: - ----- Method: WriteBarrierTest>>testBecomeReadOnly (in category 'tests - object') ----- - testBecomeReadOnly - | readOnlyArrays readOnlyByteArrays | - readOnlyArrays := (1 to: 3) collect: [:n| (0 to: n) asArray beReadOnlyObject; yourself]. - "N.B. if the targets are read-only this fails, which is correct for elementsForwardIdentityTo: since copyHash is implicitly true; - we need to write a test for a putative elementsForwardIdentityNoCopyHashTo:" - readOnlyByteArrays := (1 to: 3) collect: [:n| (0 to: n) asByteArray" beReadOnlyObject; yourself"]. - self should: [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] - raise: ModificationForbidden. - [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] - on: ModificationForbidden - do: [:ex| - false - ifTrue: "This fails, but should succeed. I *think* it's to do with catching signals when resignalling" - [(ex mirror detect: [:element| element isReadOnlyObject] ifNone: []) ifNotNil: - [:readOnlyObj| readOnlyObj beWritableObject]] - ifFalse: - [ex mirror do: [:element| element beWritableObject]]. - ex retryModification]. - self assert: (readOnlyArrays allSatisfy: [:array| array class == ByteArray])! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingByteAtPut (in category 'tests - object') ----- - testMutateByteArrayUsingByteAtPut - | guineaPig | - guineaPig := ByteArray new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig byteAt: 1 put: 12 ] - raise: ModificationForbidden. - - [ guineaPig byteAt: 1 put: 12 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: 12. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - self - should: [ guineaPig byteAt: 1 put: 13 ] - raise: ModificationForbidden. - - [ guineaPig byteAt: 1 put: 13 ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig first equals: 13. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingDoubleAtPut (in category 'tests - object') ----- - testMutateByteArrayUsingDoubleAtPut - | guineaPig | - guineaPig := ByteArray new: 8. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] - raise: ModificationForbidden. - - [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: (2 raisedTo: 65) asFloat. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - self - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] - raise: ModificationForbidden. - - [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig first equals: (2 raisedTo: 64) asFloat. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingFloatAtPut (in category 'tests - object') ----- - testMutateByteArrayUsingFloatAtPut - | guineaPig | - guineaPig := ByteArray new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig floatAt: 1 put: 1.0 ] - raise: ModificationForbidden. - - [ guineaPig floatAt: 1 put: 1.0 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: 1.0. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - - self - should: [ guineaPig floatAt: 1 put: 2.0 ] - raise: ModificationForbidden. - - [ guineaPig floatAt: 1 put: 2.0 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig first equals: 2.0. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingAtPut (in category 'tests - object') ----- - testMutateByteStringyUsingAtPut - | guineaPig | - guineaPig := ByteString new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: $h ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: $h ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: $h. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: $g ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: $g ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume ]. - - self assert: guineaPig first equals: $g. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingByteAtPut (in category 'tests - object') ----- - testMutateByteStringyUsingByteAtPut - | guineaPig | - guineaPig := ByteString new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig byteAt: 1 put: 100 ] - raise: ModificationForbidden. - - [ guineaPig byteAt: 1 put: 100 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first asciiValue equals: 100! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteSymbolUsingPrivateAtPut (in category 'tests - object') ----- - testMutateByteSymbolUsingPrivateAtPut - | guineaPig | - [guineaPig := #hello. - guineaPig beReadOnlyObject. - - self - should: ((guineaPig class includesSelector: #pvtAt:put:) - ifTrue: [[ guineaPig perform: #pvtAt:put: with: 1 with: $q ]] "Squeak refuses to compile non-self sends of pvt* selectors." - ifFalse: [[ guineaPig privateAt: 1 put: $q ]]) - raise: ModificationForbidden ] - ensure: - [ guineaPig beWritableObject ]. - - self assert: guineaPig first equals: $h! Item was removed: - ----- Method: WriteBarrierTest>>testMutateIVObject (in category 'tests - object') ----- - testMutateIVObject - | guineaPig | - guineaPig := MessageSend new. - guineaPig beReadOnlyObject. - [ guineaPig receiver: 1 ] - on: ModificationForbidden - do: [ :modification | "Surely a NoModification error" ]. - guineaPig - beWritableObject; - selector: #+; - beReadOnlyObject. - [ guineaPig arguments: #(2) ] - on: ModificationForbidden - do: [ :modification |"Surely a NoModification error" ]. - self assert: guineaPig receiver isNil. - self assert: guineaPig arguments isNil. - self assert: guineaPig selector == #+.! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectClass (in category 'tests - object') ----- - testMutateObjectClass - | guineaPig | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] - raise: ModificationForbidden. - - [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig class equals: WriteBarrierAnotherStub! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectClassViaAdoption (in category 'tests - object') ----- - testMutateObjectClassViaAdoption - | guineaPig | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - - self - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - raise: ModificationForbidden. - - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig class equals: WriteBarrierAnotherStub. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - self - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - raise: ModificationForbidden. - - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig class equals: WriteBarrierAnotherStub. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectFirstInstVarWithManyVars (in category 'tests - object') ----- - testMutateObjectFirstInstVarWithManyVars - | guineaPig failure | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - failure := [ guineaPig var1: #test ] on: ModificationForbidden do: [:err | err]. - - self assert: failure fieldIndex equals: 1! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarShouldCatchRightFailure (in category 'tests - object') ----- - testMutateObjectInstVarShouldCatchRightFailure - | guineaPig failure | - guineaPig := MessageSend new. - guineaPig beReadOnlyObject. - failure := [ guineaPig receiver: #test ] on: ModificationForbidden do: [:err | err]. - - self assert: failure object == guineaPig. - self assert: failure newValue equals: #test. - self assert: failure fieldIndex equals: 1.! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingAtPut (in category 'tests - object') ----- - testMutateObjectInstVarUsingAtPut - | guineaPig | - guineaPig := Array new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: #test. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume ]. - - self assert: guineaPig first equals: #test. - self assert: guineaPig isReadOnlyObject - ! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingBasicAtPut (in category 'tests - object') ----- - testMutateObjectInstVarUsingBasicAtPut - | guineaPig | - guineaPig := Array new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig basicAt: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: #test! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingInstVarAtPut (in category 'tests - object') ----- - testMutateObjectInstVarUsingInstVarAtPut - | guineaPig | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig instVarAt: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig instVarAt: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig var1 equals: #test! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectLastInstVarWithManyVars (in category 'tests - object') ----- - testMutateObjectLastInstVarWithManyVars - | guineaPig failure | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - failure := [ guineaPig var10: #test ] on: ModificationForbidden do: [:err | err]. - - self assert: failure fieldIndex equals: 10! Item was removed: - ----- Method: WriteBarrierTest>>testMutateVariableObject (in category 'tests - object') ----- - testMutateVariableObject - | guineaPigs | - guineaPigs := {#[1 2 3] . #(1 2 3) }. - guineaPigs do: [ :guineaPig | - guineaPig beReadOnlyObject. - [guineaPig at: 1 put: 4] - on: ModificationForbidden - do: [ "Surely a NoModification error" ]. - guineaPig - beWritableObject; - at: 2 put: 5; - beReadOnlyObject. - [guineaPig at: 3 put: 6] - on: ModificationForbidden - do: [ "Surely a NoModification error" ]. - self assert: guineaPig first = 1. - self assert: guineaPig second = 5. - self assert: guineaPig third = 3 ]! Item was removed: - ----- Method: WriteBarrierTest>>testMutateWideStringUsingAtPut (in category 'tests - object') ----- - testMutateWideStringUsingAtPut - | guineaPig | - guineaPig := 'hello' asWideString. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: $q ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: $q ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: $q! Item was removed: - ----- Method: WriteBarrierTest>>testMutateWideStringUsingWordAtPut (in category 'tests - object') ----- - testMutateWideStringUsingWordAtPut - | guineaPig | - guineaPig := 'hello' asWideString. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig wordAt: 1 put: 65536 ] - raise: ModificationForbidden. - - [ guineaPig wordAt: 1 put: 65536 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first asciiValue equals: 65536! Item was removed: - ----- Method: WriteBarrierTest>>testMutateWideSymbolUsingPrivateAtPut (in category 'tests - object') ----- - testMutateWideSymbolUsingPrivateAtPut - | guineaPig | - [ guineaPig := ('hello', (Character codePoint: 8002) asString) asSymbol. - guineaPig beReadOnlyObject. - - self - should: ((guineaPig class includesSelector: #pvtAt:put:) - ifTrue: [[ guineaPig perform: #pvtAt:put: with: 1 with: $A ]] "Squeak refuses to compile non-self sends of pvt* selectors." - ifFalse: [[ guineaPig privateAt: 1 put: $A ]]) - raise: ModificationForbidden ] - ensure: [ guineaPig beWritableObject ]. - - self assert: guineaPig first equals: $h! Item was removed: - ----- Method: WriteBarrierTest>>testObject:initialState:tuples: (in category 'tests - helper') ----- - testObject: object initialState: initialState tuples: tuples - self - testObject: object - initialState: initialState - tuples: tuples - setReadOnlyBlock: [ :value | object setIsReadOnlyObject: value ]! Item was removed: - ----- Method: WriteBarrierTest>>testObject:initialState:tuples:setReadOnlyBlock: (in category 'tests - helper') ----- - testObject: object initialState: initialState tuples: tuples setReadOnlyBlock: setImmutabilityBlock - self assert: object isReadOnlyObject equals: initialState. - tuples do: [ :tuple | - | stateToSet expectedResult expectedNewState | - stateToSet := tuple first. - expectedResult := tuple second. - expectedNewState := tuple last. - [self assert: (setImmutabilityBlock value: stateToSet) equals: expectedResult ] - on: ((Smalltalk classNamed: #PrimitiveFailed) ifNil: [Error]) - do: [ self assert: (self alwaysReadOnlyObjects , self alwaysWritableObjects includes: object) ]. - self assert: object isReadOnlyObject equals: expectedNewState ]! Item was removed: - ----- Method: WriteBarrierTest>>testProxyObject:initialState:tuples: (in category 'tests - helper') ----- - testProxyObject: object initialState: initialState tuples: tuples - self - testObject: object - initialState: initialState - tuples: tuples - setReadOnlyBlock: [ :value | - MirrorPrimitives makeObject: object readOnly: value ]! Item was removed: - ----- Method: WriteBarrierTest>>testRetryingInstVarModification (in category 'tests - object') ----- - testRetryingInstVarModification - | guineaPig | - guineaPig := MessageSend new. - guineaPig beReadOnlyObject. - - [ guineaPig receiver: 1 ] on: ModificationForbidden do: [:err | - guineaPig beWritableObject. - err retryModification ]. - - self assert: guineaPig receiver equals: 1! Item was removed: - ----- Method: WriteBarrierTest>>testRetryingPointInstVarModification (in category 'tests - object') ----- - testRetryingPointInstVarModification - | guineaPig labRat | - guineaPig := 1 at 2. - labRat := guineaPig copy bitShiftPoint: 3. - guineaPig beReadOnlyObject. - - [ guineaPig bitShiftPoint: 3 ] - on: ModificationForbidden - do: [:err | - guineaPig beWritableObject. - err retryModification ]. - - self assert: guineaPig equals: labRat. - self deny: guineaPig isReadOnlyObject. - - guineaPig bitShiftPoint: -3; beReadOnlyObject. - self assert: guineaPig equals: 1 at 2. - - [ guineaPig bitShiftPoint: 3 ] - on: ModificationForbidden - do: [:err | - guineaPig beWritableObject. - err retryModificationNoResume. - guineaPig beReadOnlyObject. - err resume ]. - - self assert: guineaPig equals: labRat. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyFailure (in category 'tests - object') ----- - testSetIsReadOnlyFailure - self alwaysWritableObjects do: [ :each | - self - testObject: each - initialState: false - tuples: #( (true false false) (false false false) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyFailureProxy (in category 'tests - proxy') ----- - testSetIsReadOnlyFailureProxy - self alwaysWritableObjects do: [ :each | - self - testProxyObject: each - initialState: false - tuples: #( (true false false) (false false false) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyImmediate (in category 'tests - object') ----- - testSetIsReadOnlyImmediate - self alwaysReadOnlyObjects do: [ :each | - self - testObject: each - initialState: true - tuples: #( (true true true) (false true true) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyImmediateProxy (in category 'tests - proxy') ----- - testSetIsReadOnlyImmediateProxy - self alwaysReadOnlyObjects do: [ :each | - self - testProxyObject: each - initialState: true - tuples: #( (true true true) (false true true) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlySuccess (in category 'tests - object') ----- - testSetIsReadOnlySuccess - self maybeReadOnlyObjects do: [ :each | - self - testObject: each - initialState: false - tuples: #( (true false true) (false true false) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlySuccessProxy (in category 'tests - proxy') ----- - testSetIsReadOnlySuccessProxy - self maybeReadOnlyObjects do: [ :each | - self - testProxyObject: each - initialState: false - tuples: #( (true false true) (false true false) ) ]! From commits at source.squeak.org Sat Mar 20 18:21:05 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sat, 20 Mar 2021 18:21:05 0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1383.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1383.mcz ==================== Summary ==================== Name: Kernel-ct.1383 Author: ct Time: 20 March 2021, 7:21:02.280742 pm UUID: b1953f95-408a-aa4a-9108-cc1dc355e9d1 Ancestors: Kernel-mt.1381 Fixes simulation of the #perform:... primitives 83, 84, and 100 for all edge cases. If the primitive is called with the wrong arguments, the primitive must fail but not the simulator. For further reference, see also the implementation of primitive 188 (primitiveExecuteMethodArgsArray) just a few lines below. :-) Tests have been provided in KernelTests-ct.395. Reuploaded to fix mirror variant of primitive 100. Now it's finally possible to debug MirrorPrimitiveTests>>#testMirrorPerform. Replaces Kernel-ct.1367, which can be moved into the treated inbox. =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" + [| selector | + selector := arguments at: 1 ifAbsent: + [^ self class primitiveFailTokenFor: #'bad argument']. + arguments size - 1 = selector numArgs ifFalse: + [^ self class primitiveFailTokenFor: #'bad number of arguments']. + ^self send: selector to: receiver with: arguments allButFirst]. - [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" + [| selector args | + arguments size = 2 ifFalse: + [^ self class primitiveFailTokenFor: #'bad argument']. + selector := arguments first. + args := arguments second. + args isArray ifFalse: + [^ self class primitiveFailTokenFor: #'bad argument']. + args size = selector numArgs ifFalse: + [^ self class primitiveFailTokenFor: #'bad number of arguments']. + ^self send: selector to: receiver with: args]. - [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" + [| rcvr selector args superclass | + arguments size + caseOf: { + [3] -> [ + rcvr := receiver. + selector := arguments first. + args := arguments second. + superclass := arguments third]. + [4] -> ["mirror primitive" + rcvr := arguments first. + selector := arguments second. + args := arguments third. + superclass := arguments fourth] } + otherwise: [^ self class primitiveFailTokenFor: #'bad argument']. + args isArray ifFalse: + [^ self class primitiveFailTokenFor: #'bad argument']. + args size = selector numArgs ifFalse: + [^ self class primitiveFailTokenFor: #'bad number of arguments']. + ((self objectClass: rcvr) includesBehavior: superclass) ifFalse: + [^ self class primitiveFailTokenFor: #'bad argument']. + ^self send: selector to: rcvr with: args lookupIn: superclass]. - [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: [| effective | effective := Processor activeProcess effectiveProcess. "active == effective" value := primitiveIndex = 186 ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! From Christoph.Thiede at student.hpi.uni-potsdam.de Sat Mar 20 18:25:03 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sat, 20 Mar 2021 18:25:03 +0000 Subject: [squeak-dev] Hang up your image using primitive 118 Message-ID: ar := #(118 nil) copy. ar at: 2 put: ar. 2 tryPrimitive: 118 withArgs: ar. "Crash!" I'm not sure whether I should be glad that 118 has no arbitrary limitations on recursion, or whether I should be sad because the image crashes. I think I'll decide for the first option. :-) BTW: The example also infinite-loops as expected in the simulator. Nice work! Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Sat Mar 20 18:25:51 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sat, 20 Mar 2021 18:25:51 +0000 Subject: [squeak-dev] The Inbox: KernelTests-ct.395.mcz In-Reply-To: References: Message-ID: Hmm, the diff is broken ... Looked fine in my image. :-( Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Samstag, 20. März 2021 19:17:50 An: squeak-dev at lists.squeakfoundation.org Betreff: [squeak-dev] The Inbox: KernelTests-ct.395.mcz A new version of KernelTests was added to project The Inbox: http://source.squeak.org/inbox/KernelTests-ct.395.mcz ==================== Summary ==================== Name: KernelTests-ct.395 Author: ct Time: 20 March 2021, 7:17:49.390742 pm UUID: 76e4d450-32dd-d24c-8aad-68ad212ec955 Ancestors: KernelTests-mt.394, KernelTests-ct.375 Tests simulation of #perform:... primitives 83, 84, and 100. Complements Kernel-ct.1367. Reuploaded to add another fixture for the mirror primitive variant of primitive 100. Corrected order of assertion arguments. Replaces KernelTests-ct.38{2,3}, which can be moved into the treated inbox. Depends indeed not only on KernelTests-mt.394 but also on KernelTests-ct.375, it would be nice if we could get the latter merged soon, this has already been causing too many merge conflicts in the past. :-) =============== Diff against KernelTests-mt.394 =============== Item was changed: SystemOrganization addCategory: #'KernelTests-Classes'! SystemOrganization addCategory: #'KernelTests-Methods'! SystemOrganization addCategory: #'KernelTests-Numbers'! SystemOrganization addCategory: #'KernelTests-Objects'! SystemOrganization addCategory: #'KernelTests-Processes'! - SystemOrganization addCategory: #'KernelTests-WriteBarrier'! - SystemOrganization addCategory: #'KernelTests-Models'! Item was changed: ----- Method: AllocationTest>>testOutOfMemorySignal (in category 'tests') ----- testOutOfMemorySignal + "Ensure that OutOfMemory is signaled eventually" - "Ensure that OutOfMemory is signaled eventually. Restrain the available memory first to not stress the machine too much." - | sz | self setFreeSpaceLimitOf: 1024 * 1024 * 1024 * (Smalltalk wordSize = 8 ifTrue: [4] ifFalse: [1.5]) around: [sz := 512*1024*1024. "work around the 1GB alloc bug" + self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory]. + + "Call me when this test fails, I want your machine." + "Current (2017) Spur VMs fail new: & basicNew: with #'bad argument' if given other than a non-negative SmallInteger." + sz := 1024*1024*1024*1024. + self should: [Array new: sz] + raise: OutOfMemory, Error + withExceptionDo: + [:ex| + ex class == Error ifTrue: + [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! - self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory].! Item was removed: - ----- Method: AllocationTest>>testOutOfMemorySignalExtreme (in category 'tests') ----- - testOutOfMemorySignalExtreme - "Try to allocate a ridiculous amount of memory and check whether the expected error is signaled. Call Eliot when this test fails, he want your machine. :-) - - Note that current (2017) Spur VMs fail in #new: and #basicNew: with #'bad argument' if given other than a non-negative SmallInteger. - - Also note that this test can be quite stressful to your machine depending on how your operating system allocates the required memory behind the curtains. Better not triggering some robot fetching a tape from somewhere..." - - | sz | - sz := 1024*1024*1024*1024. "= 1 TiB" - self should: [Array new: sz] - raise: OutOfMemory, Error - withExceptionDo: - [:ex| - ex class == Error ifTrue: - [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! Item was removed: - ----- Method: BlockClosureTest>>return: (in category 'private') ----- - return: something - - ^ something! Item was removed: - ----- Method: BlockClosureTest>>testMoreThanOnce (in category 'tests - evaluating') ----- - testMoreThanOnce - "Make sure that we can use once more than once" - | moreThanOnce | - moreThanOnce := (1 to: 3) collect: [:e | [String new] once -> [Array new] once]. - self assert: (moreThanOnce allSatisfy: [:each | each key isString]). - self assert: (moreThanOnce allSatisfy: [:each | each value isArray]). - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]).! Item was removed: - ----- Method: BlockClosureTest>>testMoreThanOnceForEqualBlocks (in category 'tests - evaluating') ----- - testMoreThanOnceForEqualBlocks - "Make sure that we can use once more than once" - | moreThanOnce | - moreThanOnce := (1 to: 3) collect: [:e | [Object new] once -> [Object new] once]. - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]). - self assert: (moreThanOnce noneSatisfy: [:each | each key == each value]).! Item was changed: ----- Method: BlockClosureTest>>testRunSimulated (in category 'tests') ----- testRunSimulated + self assert: Rectangle equals: (Context runSimulated: aBlockClosure asContext) class! - self assert: Rectangle equals: - (Context runSimulated: aBlockClosure asContext) class. - self assert: 42 equals: - (Context runSimulated: [self return: 42]). - self - should: [Context runSimulated: [self halt]] - raise: Halt.! Item was removed: - ----- Method: BlockClosureTest>>testRunSimulatedContextAtEachStep (in category 'tests') ----- - testRunSimulatedContextAtEachStep - - | context | - context := aBlockClosure asContext. - self assert: Rectangle equals: (thisContext - runSimulated: context - contextAtEachStep: [:ctxt | self assert: - [ctxt == context or: [ctxt hasSender: context]]]) class.! Item was changed: ----- Method: BlockClosureTest>>testSetUp (in category 'tests') ----- testSetUp "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" self deny: aBlockClosure isContext. self assert: aBlockClosure isClosure. self assert: aBlockClosure home = homeOfABlockClosure. self assert: aBlockClosure receiver = self. + self assert: aBlockClosure method isCompiledMethod! - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) - ifTrue: [aBlockClosure method isCompiledBlock] - ifFalse: [aBlockClosure method isCompiledMethod])! Item was changed: ----- Method: BlockClosureTest>>testTallyInstructions (in category 'tests') ----- testTallyInstructions + self assert: (Context tallyInstructions: aBlockClosure asContext) size = 15! - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) - ifTrue: [14] - ifFalse: [15]) - equals: (Context tallyInstructions: aBlockClosure asContext) size! Item was changed: ----- Method: ClassTest>>testChangeClassOf (in category 'tests') ----- testChangeClassOf "Exercise primitiveChangeClass (primitive 115) for a common use case. This should pass for any Squeak image format (but failed for image format 68002 prior to VM fix)" + self shouldnt: [Inspector new primitiveChangeClassTo: CompiledMethodInspector new] raise: Error! - self shouldnt: [Exception new primitiveChangeClassTo: Error new] raise: Error! Item was changed: ----- Method: CompiledMethodTest>>testClosureSize (in category 'tests - closures') ----- testClosureSize + self + assert: ((self class >> #withClosure) embeddedBlockClosures at: 1) size + equals: 2; + assert: ((self class >> #withClosureNoNLR) embeddedBlockClosures at: 1) size + equals: 2! - | compiledMethod expectedSize | - compiledMethod := (self class >> #withClosure). - expectedSize := compiledMethod bytecodeSetName - caseOf: { - ['SistaV1'] -> [3]. - ['V3PlusClosures'] -> [2]}. - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size. - compiledMethod := (self class >> #withClosureNoNLR). - expectedSize := compiledMethod bytecodeSetName - caseOf: { - ['SistaV1'] -> [3]. - ['V3PlusClosures'] -> [2]}. - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size.! Item was added: + TestCase subclass: #ContextTest + instanceVariableNames: 'aCompiledMethod aReceiver aSender aContext' + classVariableNames: '' + poolDictionaries: '' + category: 'KernelTests-Methods'! + + !ContextTest commentStamp: 'ct 1/27/2020 13:03' prior: 0! + I am an SUnit Test of Context. See also BlockClosureTest. + See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak see http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ and http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) + My fixtures are: + aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" + aSender - just some arbitrary object, thisContext + aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". + aContext - just some arbitray context ... + + ! Item was added: + ----- Method: ContextTest>>privRestartTest (in category 'private') ----- + privRestartTest + "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" + |a firstTimeThrough | + firstTimeThrough := true. + a := 10. + + self assert: 30 equals: [|b| + self assert: 10 = a . + self assert: nil == b. + b := a + 20. + firstTimeThrough ifTrue: [ + firstTimeThrough := false. + thisContext restart.]. + b] value + ! Item was added: + ----- Method: ContextTest>>setUp (in category 'running') ----- + setUp + super setUp. + aCompiledMethod := Rectangle methodDict at: #rightCenter. + aReceiver := 100 at 100 corner: 200 at 200. + aSender := thisContext. + aContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! Item was added: + ----- Method: ContextTest>>testActivateReturnValue (in category 'tests') ----- + testActivateReturnValue + self assert: (aSender activateReturn: aContext value: #()) isContext. + self assert: ((aSender activateReturn: aContext value: #()) receiver = aContext).! Item was added: + ----- Method: ContextTest>>testCopyStack (in category 'tests') ----- + testCopyStack + self assert: aContext copyStack printString = aContext printString.! Item was added: + ----- Method: ContextTest>>testFindContextSuchThat (in category 'tests') ----- + testFindContextSuchThat + self assert: (aContext findContextSuchThat: [:each| true]) printString = aContext printString. + self assert: (aContext hasContext: aContext). ! Item was added: + ----- Method: ContextTest>>testMethodContext (in category 'tests') ----- + testMethodContext + self assert: aContext home notNil. + self assert: aContext receiver notNil. + self assert: aContext method isCompiledMethod.! Item was added: + ----- Method: ContextTest>>testMethodIsBottomContext (in category 'tests') ----- + testMethodIsBottomContext + self assert: aContext bottomContext = aSender. + self assert: aContext secondFromBottom = aContext.! Item was added: + ----- Method: ContextTest>>testPrimitive100 (in category 'tests') ----- + testPrimitive100 + + { + {#isNil. {}. Object}. "valid 0-arg message" + {#=. {true}. UndefinedObject}. "valid unary message" + {#ifNil:ifNotNil:. {[2]. [:x | x]}. Object}. "valid binary message" + {{}. #=. {true}. SequenceableCollection}. "mirror primitive" + {#isNil}. "missing arguments" + {#isNil. 'not an array'}. "invalid arguments" + {#isNil. {}}. "missing lookupClass" + {#isNil. {'excess arg'}. Object}. "too many arguments" + {#=. {}. UndefinedObject}. "missing argument" + {#isNil. {}. Boolean}. "lookupClass not in inheritance chain" + } do: [:args | + self + assert: (nil tryPrimitive: 100 withArgs: args) + equals: (Context runSimulated: [nil tryPrimitive: 100 withArgs: args])].! Item was added: + ----- Method: ContextTest>>testPrimitive83 (in category 'tests') ----- + testPrimitive83 + + { + {#isNil}. "valid 0-arg message" + {#=. true}. "valid unary message" + {#ifNil:ifNotNil:. [2]. [:x | x]}. "valid binary message" + {#isNil. 'excess arg'}. "too many arguments" + {#=}. "missing argument" + } do: [:args | + self + assert: (nil tryPrimitive: 83 withArgs: args) + equals: (Context runSimulated: [nil tryPrimitive: 83 withArgs: args])].! Item was added: + ----- Method: ContextTest>>testPrimitive84 (in category 'tests') ----- + testPrimitive84 + + { + {#isNil. {}}. "valid 0-arg message" + {#=. {true}}. "valid unary message" + {#ifNil:ifNotNil:. {[2]. [:x | x]}}. "valid binary message" + {#isNil}. "missing arguments" + {#isNil. 'not an array'}. "invalid arguments" + {#isNil. {'excess arg'}}. "too many arguments" + {#=. {}}. "missing argument" + } do: [:args | + self + assert: (nil tryPrimitive: 84 withArgs: args) + equals: (Context runSimulated: [nil tryPrimitive: 84 withArgs: args])].! Item was added: + ----- Method: ContextTest>>testRestart (in category 'tests') ----- + testRestart + self should: [self privRestartTest] notTakeMoreThan: 0.1 second! Item was added: + ----- Method: ContextTest>>testReturn (in category 'tests') ----- + testReturn + "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." + aContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). + self assert: (aContext return: 5) = 5! Item was added: + ----- Method: ContextTest>>testSetUp (in category 'tests') ----- + testSetUp + "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" + self assert: aContext isContext. + self deny: aContext isExecutingBlock. + self deny: aContext isClosure. + self deny: aContext isDead. + "self assert: aMethodContext home = aReceiver." + "self assert: aMethodContext blockHome = aReceiver." + self assert: aContext receiver = aReceiver. + self assert: aContext method isCompiledMethod. + self assert: aContext method = aCompiledMethod. + self assert: aContext methodNode selector = #rightCenter. + self assert: (aContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. + self assert: aContext client printString = 'ContextTest>>#testSetUp'. + ! Item was removed: - ----- Method: FloatTest class>>testClassConstantsPasses (in category 'utilities') ----- - testClassConstantsPasses - "Answer if testClassConstants passes. This can be used in e.g. the Kernel Package prolog - to test if Float initialize needs to be run." - [self new testClassConstants] - on: TestResult failure - do: [:ex| ^false]. - ^true! Item was removed: - ----- Method: FloatTest>>assert:equals:withinUlp: (in category 'asserting') ----- - assert: expected equals: actual withinUlp: maxUlp - self assert: (expected - actual) abs <= (maxUlp * expected asFloat ulp)! Item was removed: - ----- Method: FloatTest>>floatLiteralsIn: (in category 'private') ----- - floatLiteralsIn: method - | floatLiterals | - floatLiterals := OrderedCollection new. - method allLiteralsDo: - [:lit| lit isFloat ifTrue: [floatLiterals addLast: lit]]. - ^floatLiterals! Item was removed: - ----- Method: FloatTest>>methodContainsFloatLiteral: (in category 'private') ----- - methodContainsFloatLiteral: method - method isQuick ifFalse: - [method allLiteralsDo: - [:lit| lit isFloat ifTrue: [^true]]]. - ^false! Item was removed: - ----- Method: FloatTest>>methodsMaybeContainingBrokenCompiledConstants (in category 'private') ----- - methodsMaybeContainingBrokenCompiledConstants - "Answer a set of all methods in the system which contain float constants that differ from those obtaiuned by - recompiling. These may indicate an old compiler issue, or indeed an issue with the current compiler. This is a - variant of testCompiledConstants used for collecting the set of methods rather than testing that none exist." - | identifiedPatients | - identifiedPatients := IdentitySet new. - CurrentReadOnlySourceFiles cacheDuring: - [self systemNavigation allSelectorsAndMethodsDo: - [:class :selector :method| - (self methodContainsFloatLiteral: method) ifTrue: - [| newMethodAndNode newLiterals oldLiterals | - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. - newLiterals := self floatLiteralsIn: newMethodAndNode method. - oldLiterals := self floatLiteralsIn: method. - "Convenience doit for recompiling broken methods:..." - "class recompile: selector" - newLiterals size = oldLiterals size - ifFalse: [identifiedPatients add: method] - ifTrue: - [newLiterals with: oldLiterals do: - [:new :old| - (new asIEEE64BitWord = old asIEEE64BitWord - or: [new isNaN and: old isNaN]) ifFalse: - [identifiedPatients add: method]]]]]]. - ^identifiedPatients! Item was removed: - ----- Method: FloatTest>>testClassConstants (in category 'tests - characterization') ----- - testClassConstants - - "Test all the class constants that are floats to check that they are valid. - Sometimes compiler bugs mean that the initialization method is incorrect, etc" - | expectedVariables unexpectedVariables "these two are for determining if this test is correct, not its results" - finiteVariables infiniteVariables nanVariables | - finiteVariables := #(Pi Halfpi Twopi ThreePi RadiansPerDegree Ln2 Ln10 Sqrt2 E Epsilon MaxVal MaxValLn NegativeZero). - infiniteVariables := #(Infinity NegativeInfinity). - nanVariables := #(NaN). - expectedVariables := Set new. - unexpectedVariables := Set new. - Float classPool keysAndValuesDo: - [:name :value| - value isFloat - ifTrue: - [(finiteVariables includes: name) ifTrue: - [expectedVariables add: name. - self assert: value isFinite. - self deny: value isInfinite. - self deny: value isNaN]. - (infiniteVariables includes: name) ifTrue: - [expectedVariables add: name. - self deny: value isFinite. - self assert: value isInfinite. - self deny: value isNaN]. - (nanVariables includes: name) ifTrue: - [expectedVariables add: name. - self deny: value isFinite. - self deny: value isInfinite. - self assert: value isNaN]. - (expectedVariables includes: name) ifFalse: - [unexpectedVariables add: name]] - ifFalse: - [self deny: ((finiteVariables includes: name) or: [(infiniteVariables includes: name) or: [nanVariables includes: name]])]]. - "Now check that test itself is working as intended..." - self assert: unexpectedVariables isEmpty. - self assert: expectedVariables = (finiteVariables, infiniteVariables, nanVariables) asSet! Item was removed: - ----- Method: FloatTest>>testCloseToFurthestCloseToNeasrest (in category 'tests - compare') ----- - testCloseToFurthestCloseToNeasrest - | x nearest furthest | - x := 1.0e-6. - nearest := 1.0e-7. - furthest := 0.0. - self assert: (x - nearest) abs < (x - furthest) abs. - self assert: (x closeTo: furthest) ==> (x closeTo: nearest)! Item was removed: - ----- Method: FloatTest>>testCloseToIsSymmetric (in category 'tests - compare') ----- - testCloseToIsSymmetric - self assert: ((1<<2000) reciprocal closeTo: 1.0e-6) equals: (1.0e-6 closeTo: (1<<2000) reciprocal)! Item was removed: - ----- Method: FloatTest>>testCompiledConstants (in category 'tests') ----- - testCompiledConstants - "Test that any methods containing a floating point literal have been correctly compiled." - CurrentReadOnlySourceFiles cacheDuring: - [self systemNavigation allSelectorsAndMethodsDo: - [:class :selector :method| - (self methodContainsFloatLiteral: method) ifTrue: - [| newMethodAndNode newLiterals oldLiterals | - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. - newLiterals := self floatLiteralsIn: newMethodAndNode method. - oldLiterals := self floatLiteralsIn: method. - "Convenience doit for recompiling broken methods:..." - "class recompile: selector" - self assert: newLiterals size = oldLiterals size. - newLiterals with: oldLiterals do: - [:new :old| - self assert: (new asIEEE64BitWord = old asIEEE64BitWord - or: [new isNaN and: old isNaN])]]]]! Item was removed: - ----- Method: FloatTest>>testLog2near1 (in category 'tests - mathematical functions') ----- - testLog2near1 - self assert: 1.0 predecessor ln / 2 ln equals: 1.0 predecessor log2 withinUlp: 2. - self assert: 1.0 successor ln / 2 ln equals: 1.0 successor log2 withinUlp: 2! Item was removed: - TestCase subclass: #MethodContextTest - instanceVariableNames: 'aCompiledMethod aReceiver aMethodContext aSender' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-Methods'! - - !MethodContextTest commentStamp: 'eem 3/30/2017 17:42' prior: 0! - I am an SUnit Test of Context. See also BlockClosureTest. - See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak see http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ and http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) - My fixtures are: - aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" - aSender - just some arbitrary object, thisContext - aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". - aMethodContext - just some arbitray context ... - - ! Item was removed: - ----- Method: MethodContextTest>>privRestartTest (in category 'private') ----- - privRestartTest - "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" - |a firstTimeThrough | - firstTimeThrough := true. - a := 10. - - self assert: 30 equals: [|b| - self assert: 10 = a . - self assert: nil == b. - b := a + 20. - firstTimeThrough ifTrue: [ - firstTimeThrough := false. - thisContext restart.]. - b] value - ! Item was removed: - ----- Method: MethodContextTest>>setUp (in category 'running') ----- - setUp - super setUp. - aCompiledMethod := Rectangle methodDict at: #rightCenter. - aReceiver := 100 at 100 corner: 200 at 200. - aSender := thisContext. - aMethodContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! Item was removed: - ----- Method: MethodContextTest>>testActivateReturnValue (in category 'tests') ----- - testActivateReturnValue - self assert: (aSender activateReturn: aMethodContext value: #()) isContext. - self assert: ((aSender activateReturn: aMethodContext value: #()) receiver = aMethodContext).! Item was removed: - ----- Method: MethodContextTest>>testCopyStack (in category 'tests') ----- - testCopyStack - self assert: aMethodContext copyStack printString = aMethodContext printString.! Item was removed: - ----- Method: MethodContextTest>>testCopyTo (in category 'tests') ----- - testCopyTo - - | context depth targetSender | - context := thisContext. - depth := 1. - targetSender := context. - [ (targetSender := targetSender sender) isNil ] whileFalse: [ - | original copy | - original := context. - copy := context copyTo: targetSender. - 1 to: depth do: [ :index | - index = 1 ifFalse: [ - "Since we're copying thisContext, the pc and stackPtr may be different for the current frame." - self - assert: original pc equals: copy pc; - assert: original stackPtr equals: copy stackPtr ]. - self - deny: original == copy; - assert: original method equals: copy method; - assert: original closure equals: copy closure; - assert: original receiver equals: copy receiver. - original := original sender. - copy := copy sender ]. - self - assert: copy isNil; - assert: original == targetSender. - depth := depth + 1 ]! Item was removed: - ----- Method: MethodContextTest>>testFindContextSuchThat (in category 'tests') ----- - testFindContextSuchThat - self assert: (aMethodContext findContextSuchThat: [:each| true]) printString = aMethodContext printString. - self assert: (aMethodContext hasContext: aMethodContext). ! Item was removed: - ----- Method: MethodContextTest>>testMethodContext (in category 'tests') ----- - testMethodContext - self assert: aMethodContext home notNil. - self assert: aMethodContext receiver notNil. - self assert: aMethodContext method isCompiledMethod.! Item was removed: - ----- Method: MethodContextTest>>testMethodIsBottomContext (in category 'tests') ----- - testMethodIsBottomContext - self assert: aMethodContext bottomContext = aSender. - self assert: aMethodContext secondFromBottom = aMethodContext.! Item was removed: - ----- Method: MethodContextTest>>testRestart (in category 'tests') ----- - testRestart - self should: [self privRestartTest] notTakeMoreThan: 0.1 second! Item was removed: - ----- Method: MethodContextTest>>testReturn (in category 'tests') ----- - testReturn - "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." - aMethodContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). - self assert: (aMethodContext return: 5) = 5! Item was removed: - ----- Method: MethodContextTest>>testSetUp (in category 'tests') ----- - testSetUp - "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" - self assert: aMethodContext isContext. - self deny: aMethodContext isExecutingBlock. - self deny: aMethodContext isClosure. - self deny: aMethodContext isDead. - "self assert: aMethodContext home = aReceiver." - "self assert: aMethodContext blockHome = aReceiver." - self assert: aMethodContext receiver = aReceiver. - self assert: aMethodContext method isCompiledMethod. - self assert: aMethodContext method = aCompiledMethod. - self assert: aMethodContext methodNode selector = #rightCenter. - self assert: (aMethodContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. - self assert: aMethodContext client printString = 'MethodContextTest>>#testSetUp'. - ! Item was removed: - TestCase subclass: #ModelTest - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-Models'! Item was removed: - ----- Method: ModelTest>>testCopyDependents (in category 'tests') ----- - testCopyDependents - - | bar foo | - foo := Model new. - foo addDependent: 42. - self assert: {42} equals: foo dependents asArray. - - bar := foo copy. - self assert: bar dependents isEmpty.! Item was removed: - ----- Method: NumberTest>>testExactLog2 (in category 'tests') ----- - testExactLog2 - -10 to: 10 do: [:i | self assert: i equals: (2 raisedToInteger: i) log2]. - Float emin - Float precision + 1 to: Float emax do: [:i | self assert: i equals: (1.0 timesTwoPower: i) log2].! Item was removed: - ----- Method: NumberTest>>testLog2doesNotOverflow (in category 'tests') ----- - testLog2doesNotOverflow - "Note: though this is not a strict identity, we can use strict Float equality here" - self assert: 3000.0 equals: ((1 bitShift: 3000) - 1) log2. - self assert: 1500.0 equals: (((1 bitShift: 3000) - 1) / (1 bitShift: 1500)) log2.! Item was removed: - ----- Method: NumberTest>>testLog2doesNotUnderflow (in category 'tests') ----- - testLog2doesNotUnderflow - "Note: though this is not a strict identity, we can use strict Float equality here" - self assert: -2000.0 equals: ((1 bitShift: 2000) - 1) reciprocal log2! Item was removed: - ----- Method: ObjectTest>>testCopyDependents (in category 'tests') ----- - testCopyDependents - - | bar foo | - foo := Object new. - foo addDependent: 42. - self assert: {42} equals: foo dependents asArray. - - bar := foo copy. - self assert: bar dependents isEmpty.! Item was removed: - ----- Method: ProcessTest>>genuineProcess (in category 'support') ----- - genuineProcess - - "Usually, we don't want to expose this from the class under test." - ^ Processor instVarNamed: 'genuineProcess'! Item was removed: - ----- Method: ProcessTest>>testEvaluateOnBehalfOf (in category 'tests') ----- - testEvaluateOnBehalfOf - - | p1 p2 sem results | - self genuineProcess == Processor activeProcess - ifFalse: [self fail: 'Cannot debug this test']. - - sem := Semaphore new. - p1 := [] newProcess. - p1 environmentAt: #foo put: 1. - p2 := [ - Processor activeProcess environmentAt: #foo put: 2. - results := { - Processor activeProcess environmentAt: #foo. - self genuineProcess environmentAt: #foo. - Processor activeProcess - evaluate: [Processor activeProcess environmentAt: #foo] - onBehalfOf: p1. - Processor activeProcess - evaluate: [self genuineProcess environmentAt: #foo] - onBehalfOf: p1. - Processor activeProcess environmentAt: #foo }. - sem signal - ] newProcess. - - p2 resume. - sem wait. - - self assert: {2. 2. 1. 2. 2} equals: results.! Item was removed: - ----- Method: ProcessTest>>testProcessFaithfulRunning (in category 'tests') ----- - testProcessFaithfulRunning - "While simulating a process using #runUntilErrorOrReturnFrom:, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." - - | process result | - process := Process forBlock: [ - result := Processor activeProcess environmentAt: #foo]. - process environmentAt: #foo put: 42. - - process complete: process suspendedContext. - - self assert: 42 equals: result.! Item was removed: - ----- Method: ProcessTest>>testProcessFaithfulSimulation (in category 'tests') ----- - testProcessFaithfulSimulation - "While simulating a process using the bytecode simulation machinery, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." - - | process result | - process := Process forBlock: [ - result := Processor activeProcess environmentAt: #foo]. - process environmentAt: #foo put: 42. - - process runUntil: [:context | context isDead]. - - self assert: 42 equals: result.! Item was removed: - ----- Method: PromiseTest>>testAnErrorInOnRejectedRejectsPromise (in category 'tests - monad') ----- - testAnErrorInOnRejectedRejectsPromise - "https://promisesaplus.com section 2.2.7.2" - | p q error | - p := Promise new. - q := p ifRejected: [:e | (error := KeyNotFound new) signal]. - p rejectWith: 1. - self assert: p isRejected description: 'Original Promise not rejected'. - self assert: q isRejected description: 'Broken Promise not rejected'. - self assert: p error = 1. - self assert: q error == error.! Item was changed: ----- Method: PromiseTest>>testAnErrorInThenRejectsPromise (in category 'tests - monad') ----- testAnErrorInThenRejectsPromise + | p q | - "https://promisesaplus.com section 2.2.7.2" - | p q error | p := Promise new. + q := p then: [:v | KeyNotFound signal]. - q := p then: [:v | (error := KeyNotFound new) signal]. p resolveWith: 1. self deny: p isRejected description: 'Original Promise rejected'. + self assert: q isRejected description: 'Broken Promise not rejected'.! - self assert: q isRejected description: 'Broken Promise not rejected'. - self assert: p value = 1. - self assert: q error == error.! Item was removed: - ----- Method: PromiseTest>>testNilErrBlockPropagation (in category 'tests - monad') ----- - testNilErrBlockPropagation - "https://promisesaplus.com section 2.2.7.4" - | p q | - p := Promise new. - q := p then: [:v | self error: 'Shouldn''t call resolvedBlock'] ifRejected: nil. - p rejectWith: 1. - self assert: p isRejected. - self assert: q isRejected. - self assert: p error equals: 1. - self assert: q error equals: 1.! Item was removed: - ----- Method: PromiseTest>>testNilResolvedBlockPropagation (in category 'tests - monad') ----- - testNilResolvedBlockPropagation - "https://promisesaplus.com section 2.2.7.3" - | p q | - p := Promise new. - q := p then: nil ifRejected: [:e | self error: 'Shouldn''t call errBlock']. - p resolveWith: 1. - self assert: p isResolved. - self assert: q isResolved. - self assert: p value equals: 1. - self assert: q value equals: 1.! Item was changed: ----- Method: PromiseTest>>testifRejectedRunsBlockIfPromiseFails (in category 'tests - monad') ----- testifRejectedRunsBlockIfPromiseFails - "https://promisesaplus.com section 2.2.7.1" | p q error | error := nil. p := Promise new. + q := p ifRejected: [:e | error := e]. - q := p ifRejected: [:e | error := e "N.B. returns a value, does not signal an Exception"]. p rejectWith: KeyNotFound new. + self assert: q isRejected. + self assert: KeyNotFound equals: error class.! - self assert: q isResolved. - self assert: KeyNotFound equals: error class. - self assert: q value == error.! Item was removed: - Object subclass: #WriteBarrierAnotherStub - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-WriteBarrier'! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var1 (in category 'accessing') ----- - var1 - ^ var1! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var10 (in category 'accessing') ----- - var10 - ^ var10! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var10: (in category 'accessing') ----- - var10: anObject - var10 := anObject! Item was removed: - ----- Method: WriteBarrierAnotherStub>>var1: (in category 'accessing') ----- - var1: anObject - var1 := anObject! Item was removed: - Object subclass: #WriteBarrierStub - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' - classVariableNames: '' - poolDictionaries: '' - category: 'KernelTests-WriteBarrier'! Item was removed: - ----- Method: WriteBarrierStub>>var1 (in category 'accessing') ----- - var1 - ^ var1! Item was removed: - ----- Method: WriteBarrierStub>>var10 (in category 'accessing') ----- - var10 - ^ var10! Item was removed: - ----- Method: WriteBarrierStub>>var10: (in category 'accessing') ----- - var10: anObject - var10 := anObject! Item was removed: - ----- Method: WriteBarrierStub>>var1: (in category 'accessing') ----- - var1: anObject - var1 := anObject! Item was removed: - TestCase subclass: #WriteBarrierTest - instanceVariableNames: '' - classVariableNames: 'ContextInstance' - poolDictionaries: '' - category: 'KernelTests-WriteBarrier'! - - !WriteBarrierTest commentStamp: '' prior: 0! - My tests ensure the ReadOnly property of objects work properly. - - #testMutateIVObject is a good start to understand what is going on. - - The VM needs to be compiled with -DIMMUTABILTY= true for those tests to work.! Item was removed: - ----- Method: WriteBarrierTest class>>initialize (in category 'initialization') ----- - initialize - - ContextInstance := Context sender: nil receiver: self new method: self >> #alwaysWritableObjects arguments: #()! Item was removed: - ----- Method: WriteBarrierTest>>alwaysReadOnlyObjects (in category 'guinea pigs') ----- - alwaysReadOnlyObjects - "Immediates are always immutable" - ^ { 1 }! Item was removed: - ----- Method: WriteBarrierTest>>alwaysWritableObjects (in category 'guinea pigs') ----- - alwaysWritableObjects - "Objects that currently can't be immutable" - ^ { ContextInstance . - Processor . - Processor activeProcess }! Item was removed: - ----- Method: WriteBarrierTest>>expectedFailures (in category 'expected failures') ----- - expectedFailures - Smalltalk supportsReadOnlyObjects ifFalse: - [^self class testSelectors]. - ^#( testMutateByteArrayUsingDoubleAtPut testMutateByteArrayUsingFloatAtPut ), - ((Smalltalk classNamed: #MirrorPrimitives) - ifNil: [#(testBasicProxyReadOnly testBasicProxyWritable testSetIsReadOnlySuccessProxy)] - ifNotNil: [#()])! Item was removed: - ----- Method: WriteBarrierTest>>maybeReadOnlyObjects (in category 'guinea pigs') ----- - maybeReadOnlyObjects - "ByteObject, Variable object, fixed sized object" - ^ { { 1 . 2 . 3 } asByteArray . { 1 . 2 . 3 } . (MessageSend receiver: 1 selector: #+ argument: 2) }! Item was removed: - ----- Method: WriteBarrierTest>>testAttemptToMutateLiterals (in category 'tests - object') ----- - testAttemptToMutateLiterals - | guineaPigs | - guineaPigs := {#[1 2 3] . #(1 2 3) }. - guineaPigs do: - [ :guineaPig | - self should: [guineaPig at: 1 put: 4] - raise: ModificationForbidden]. - - self should: [guineaPigs first become: guineaPigs second ] - raise: ModificationForbidden. - - self should: [ByteString adoptInstance: guineaPigs first] - raise: ModificationForbidden. - - self should: [WeakArray adoptInstance: guineaPigs last] - raise: ModificationForbidden! Item was removed: - ----- Method: WriteBarrierTest>>testBasicProxyReadOnly (in category 'tests - proxy') ----- - testBasicProxyReadOnly - self alwaysReadOnlyObjects do: [ :each | - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: true ]! Item was removed: - ----- Method: WriteBarrierTest>>testBasicProxyWritable (in category 'tests - proxy') ----- - testBasicProxyWritable - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: false ]! Item was removed: - ----- Method: WriteBarrierTest>>testBasicReadOnly (in category 'tests - object') ----- - testBasicReadOnly - self alwaysReadOnlyObjects do: [ :each | - self assert: each isReadOnlyObject equals: true ]! Item was removed: - ----- Method: WriteBarrierTest>>testBasicWritable (in category 'tests - object') ----- - testBasicWritable - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | - self assert: each isReadOnlyObject equals: false ]! Item was removed: - ----- Method: WriteBarrierTest>>testBecomeReadOnly (in category 'tests - object') ----- - testBecomeReadOnly - | readOnlyArrays readOnlyByteArrays | - readOnlyArrays := (1 to: 3) collect: [:n| (0 to: n) asArray beReadOnlyObject; yourself]. - "N.B. if the targets are read-only this fails, which is correct for elementsForwardIdentityTo: since copyHash is implicitly true; - we need to write a test for a putative elementsForwardIdentityNoCopyHashTo:" - readOnlyByteArrays := (1 to: 3) collect: [:n| (0 to: n) asByteArray" beReadOnlyObject; yourself"]. - self should: [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] - raise: ModificationForbidden. - [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] - on: ModificationForbidden - do: [:ex| - false - ifTrue: "This fails, but should succeed. I *think* it's to do with catching signals when resignalling" - [(ex mirror detect: [:element| element isReadOnlyObject] ifNone: []) ifNotNil: - [:readOnlyObj| readOnlyObj beWritableObject]] - ifFalse: - [ex mirror do: [:element| element beWritableObject]]. - ex retryModification]. - self assert: (readOnlyArrays allSatisfy: [:array| array class == ByteArray])! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingByteAtPut (in category 'tests - object') ----- - testMutateByteArrayUsingByteAtPut - | guineaPig | - guineaPig := ByteArray new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig byteAt: 1 put: 12 ] - raise: ModificationForbidden. - - [ guineaPig byteAt: 1 put: 12 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: 12. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - self - should: [ guineaPig byteAt: 1 put: 13 ] - raise: ModificationForbidden. - - [ guineaPig byteAt: 1 put: 13 ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig first equals: 13. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingDoubleAtPut (in category 'tests - object') ----- - testMutateByteArrayUsingDoubleAtPut - | guineaPig | - guineaPig := ByteArray new: 8. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] - raise: ModificationForbidden. - - [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: (2 raisedTo: 65) asFloat. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - self - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] - raise: ModificationForbidden. - - [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig first equals: (2 raisedTo: 64) asFloat. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingFloatAtPut (in category 'tests - object') ----- - testMutateByteArrayUsingFloatAtPut - | guineaPig | - guineaPig := ByteArray new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig floatAt: 1 put: 1.0 ] - raise: ModificationForbidden. - - [ guineaPig floatAt: 1 put: 1.0 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: 1.0. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - - self - should: [ guineaPig floatAt: 1 put: 2.0 ] - raise: ModificationForbidden. - - [ guineaPig floatAt: 1 put: 2.0 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig first equals: 2.0. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingAtPut (in category 'tests - object') ----- - testMutateByteStringyUsingAtPut - | guineaPig | - guineaPig := ByteString new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: $h ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: $h ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: $h. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: $g ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: $g ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume ]. - - self assert: guineaPig first equals: $g. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingByteAtPut (in category 'tests - object') ----- - testMutateByteStringyUsingByteAtPut - | guineaPig | - guineaPig := ByteString new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig byteAt: 1 put: 100 ] - raise: ModificationForbidden. - - [ guineaPig byteAt: 1 put: 100 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first asciiValue equals: 100! Item was removed: - ----- Method: WriteBarrierTest>>testMutateByteSymbolUsingPrivateAtPut (in category 'tests - object') ----- - testMutateByteSymbolUsingPrivateAtPut - | guineaPig | - [guineaPig := #hello. - guineaPig beReadOnlyObject. - - self - should: ((guineaPig class includesSelector: #pvtAt:put:) - ifTrue: [[ guineaPig perform: #pvtAt:put: with: 1 with: $q ]] "Squeak refuses to compile non-self sends of pvt* selectors." - ifFalse: [[ guineaPig privateAt: 1 put: $q ]]) - raise: ModificationForbidden ] - ensure: - [ guineaPig beWritableObject ]. - - self assert: guineaPig first equals: $h! Item was removed: - ----- Method: WriteBarrierTest>>testMutateIVObject (in category 'tests - object') ----- - testMutateIVObject - | guineaPig | - guineaPig := MessageSend new. - guineaPig beReadOnlyObject. - [ guineaPig receiver: 1 ] - on: ModificationForbidden - do: [ :modification | "Surely a NoModification error" ]. - guineaPig - beWritableObject; - selector: #+; - beReadOnlyObject. - [ guineaPig arguments: #(2) ] - on: ModificationForbidden - do: [ :modification |"Surely a NoModification error" ]. - self assert: guineaPig receiver isNil. - self assert: guineaPig arguments isNil. - self assert: guineaPig selector == #+.! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectClass (in category 'tests - object') ----- - testMutateObjectClass - | guineaPig | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] - raise: ModificationForbidden. - - [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig class equals: WriteBarrierAnotherStub! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectClassViaAdoption (in category 'tests - object') ----- - testMutateObjectClassViaAdoption - | guineaPig | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - - self - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - raise: ModificationForbidden. - - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig class equals: WriteBarrierAnotherStub. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - self - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - raise: ModificationForbidden. - - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] - on: ModificationForbidden - do: [ :modification | - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume]. - - self assert: guineaPig class equals: WriteBarrierAnotherStub. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectFirstInstVarWithManyVars (in category 'tests - object') ----- - testMutateObjectFirstInstVarWithManyVars - | guineaPig failure | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - failure := [ guineaPig var1: #test ] on: ModificationForbidden do: [:err | err]. - - self assert: failure fieldIndex equals: 1! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarShouldCatchRightFailure (in category 'tests - object') ----- - testMutateObjectInstVarShouldCatchRightFailure - | guineaPig failure | - guineaPig := MessageSend new. - guineaPig beReadOnlyObject. - failure := [ guineaPig receiver: #test ] on: ModificationForbidden do: [:err | err]. - - self assert: failure object == guineaPig. - self assert: failure newValue equals: #test. - self assert: failure fieldIndex equals: 1.! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingAtPut (in category 'tests - object') ----- - testMutateObjectInstVarUsingAtPut - | guineaPig | - guineaPig := Array new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: #test. - self deny: guineaPig isReadOnlyObject. - - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModificationNoResume. - modification object beReadOnlyObject. - modification resume ]. - - self assert: guineaPig first equals: #test. - self assert: guineaPig isReadOnlyObject - ! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingBasicAtPut (in category 'tests - object') ----- - testMutateObjectInstVarUsingBasicAtPut - | guineaPig | - guineaPig := Array new: 5. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig basicAt: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: #test! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingInstVarAtPut (in category 'tests - object') ----- - testMutateObjectInstVarUsingInstVarAtPut - | guineaPig | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig instVarAt: 1 put: #test ] - raise: ModificationForbidden. - - [ guineaPig instVarAt: 1 put: #test ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig var1 equals: #test! Item was removed: - ----- Method: WriteBarrierTest>>testMutateObjectLastInstVarWithManyVars (in category 'tests - object') ----- - testMutateObjectLastInstVarWithManyVars - | guineaPig failure | - guineaPig := WriteBarrierStub new. - guineaPig beReadOnlyObject. - failure := [ guineaPig var10: #test ] on: ModificationForbidden do: [:err | err]. - - self assert: failure fieldIndex equals: 10! Item was removed: - ----- Method: WriteBarrierTest>>testMutateVariableObject (in category 'tests - object') ----- - testMutateVariableObject - | guineaPigs | - guineaPigs := {#[1 2 3] . #(1 2 3) }. - guineaPigs do: [ :guineaPig | - guineaPig beReadOnlyObject. - [guineaPig at: 1 put: 4] - on: ModificationForbidden - do: [ "Surely a NoModification error" ]. - guineaPig - beWritableObject; - at: 2 put: 5; - beReadOnlyObject. - [guineaPig at: 3 put: 6] - on: ModificationForbidden - do: [ "Surely a NoModification error" ]. - self assert: guineaPig first = 1. - self assert: guineaPig second = 5. - self assert: guineaPig third = 3 ]! Item was removed: - ----- Method: WriteBarrierTest>>testMutateWideStringUsingAtPut (in category 'tests - object') ----- - testMutateWideStringUsingAtPut - | guineaPig | - guineaPig := 'hello' asWideString. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig at: 1 put: $q ] - raise: ModificationForbidden. - - [ guineaPig at: 1 put: $q ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first equals: $q! Item was removed: - ----- Method: WriteBarrierTest>>testMutateWideStringUsingWordAtPut (in category 'tests - object') ----- - testMutateWideStringUsingWordAtPut - | guineaPig | - guineaPig := 'hello' asWideString. - guineaPig beReadOnlyObject. - - self - should: [ guineaPig wordAt: 1 put: 65536 ] - raise: ModificationForbidden. - - [ guineaPig wordAt: 1 put: 65536 ] - on: ModificationForbidden - do: [:modification | - self assert: modification fieldIndex equals: 1. - modification object beWritableObject. - modification retryModification ]. - - self assert: guineaPig first asciiValue equals: 65536! Item was removed: - ----- Method: WriteBarrierTest>>testMutateWideSymbolUsingPrivateAtPut (in category 'tests - object') ----- - testMutateWideSymbolUsingPrivateAtPut - | guineaPig | - [ guineaPig := ('hello', (Character codePoint: 8002) asString) asSymbol. - guineaPig beReadOnlyObject. - - self - should: ((guineaPig class includesSelector: #pvtAt:put:) - ifTrue: [[ guineaPig perform: #pvtAt:put: with: 1 with: $A ]] "Squeak refuses to compile non-self sends of pvt* selectors." - ifFalse: [[ guineaPig privateAt: 1 put: $A ]]) - raise: ModificationForbidden ] - ensure: [ guineaPig beWritableObject ]. - - self assert: guineaPig first equals: $h! Item was removed: - ----- Method: WriteBarrierTest>>testObject:initialState:tuples: (in category 'tests - helper') ----- - testObject: object initialState: initialState tuples: tuples - self - testObject: object - initialState: initialState - tuples: tuples - setReadOnlyBlock: [ :value | object setIsReadOnlyObject: value ]! Item was removed: - ----- Method: WriteBarrierTest>>testObject:initialState:tuples:setReadOnlyBlock: (in category 'tests - helper') ----- - testObject: object initialState: initialState tuples: tuples setReadOnlyBlock: setImmutabilityBlock - self assert: object isReadOnlyObject equals: initialState. - tuples do: [ :tuple | - | stateToSet expectedResult expectedNewState | - stateToSet := tuple first. - expectedResult := tuple second. - expectedNewState := tuple last. - [self assert: (setImmutabilityBlock value: stateToSet) equals: expectedResult ] - on: ((Smalltalk classNamed: #PrimitiveFailed) ifNil: [Error]) - do: [ self assert: (self alwaysReadOnlyObjects , self alwaysWritableObjects includes: object) ]. - self assert: object isReadOnlyObject equals: expectedNewState ]! Item was removed: - ----- Method: WriteBarrierTest>>testProxyObject:initialState:tuples: (in category 'tests - helper') ----- - testProxyObject: object initialState: initialState tuples: tuples - self - testObject: object - initialState: initialState - tuples: tuples - setReadOnlyBlock: [ :value | - MirrorPrimitives makeObject: object readOnly: value ]! Item was removed: - ----- Method: WriteBarrierTest>>testRetryingInstVarModification (in category 'tests - object') ----- - testRetryingInstVarModification - | guineaPig | - guineaPig := MessageSend new. - guineaPig beReadOnlyObject. - - [ guineaPig receiver: 1 ] on: ModificationForbidden do: [:err | - guineaPig beWritableObject. - err retryModification ]. - - self assert: guineaPig receiver equals: 1! Item was removed: - ----- Method: WriteBarrierTest>>testRetryingPointInstVarModification (in category 'tests - object') ----- - testRetryingPointInstVarModification - | guineaPig labRat | - guineaPig := 1 at 2. - labRat := guineaPig copy bitShiftPoint: 3. - guineaPig beReadOnlyObject. - - [ guineaPig bitShiftPoint: 3 ] - on: ModificationForbidden - do: [:err | - guineaPig beWritableObject. - err retryModification ]. - - self assert: guineaPig equals: labRat. - self deny: guineaPig isReadOnlyObject. - - guineaPig bitShiftPoint: -3; beReadOnlyObject. - self assert: guineaPig equals: 1 at 2. - - [ guineaPig bitShiftPoint: 3 ] - on: ModificationForbidden - do: [:err | - guineaPig beWritableObject. - err retryModificationNoResume. - guineaPig beReadOnlyObject. - err resume ]. - - self assert: guineaPig equals: labRat. - self assert: guineaPig isReadOnlyObject! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyFailure (in category 'tests - object') ----- - testSetIsReadOnlyFailure - self alwaysWritableObjects do: [ :each | - self - testObject: each - initialState: false - tuples: #( (true false false) (false false false) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyFailureProxy (in category 'tests - proxy') ----- - testSetIsReadOnlyFailureProxy - self alwaysWritableObjects do: [ :each | - self - testProxyObject: each - initialState: false - tuples: #( (true false false) (false false false) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyImmediate (in category 'tests - object') ----- - testSetIsReadOnlyImmediate - self alwaysReadOnlyObjects do: [ :each | - self - testObject: each - initialState: true - tuples: #( (true true true) (false true true) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlyImmediateProxy (in category 'tests - proxy') ----- - testSetIsReadOnlyImmediateProxy - self alwaysReadOnlyObjects do: [ :each | - self - testProxyObject: each - initialState: true - tuples: #( (true true true) (false true true) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlySuccess (in category 'tests - object') ----- - testSetIsReadOnlySuccess - self maybeReadOnlyObjects do: [ :each | - self - testObject: each - initialState: false - tuples: #( (true false true) (false true false) ) ]! Item was removed: - ----- Method: WriteBarrierTest>>testSetIsReadOnlySuccessProxy (in category 'tests - proxy') ----- - testSetIsReadOnlySuccessProxy - self maybeReadOnlyObjects do: [ :each | - self - testProxyObject: each - initialState: false - tuples: #( (true false true) (false true false) ) ]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Sat Mar 20 18:38:52 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sat, 20 Mar 2021 18:38:52 0000 Subject: [squeak-dev] The Inbox: Kernel-ct.1384.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1384.mcz ==================== Summary ==================== Name: Kernel-ct.1384 Author: ct Time: 20 March 2021, 7:38:48.824494 pm UUID: fcf035d1-5257-5d49-ab69-048b2c308741 Ancestors: Kernel-mt.1381 Patches Process>>#stepToHome: so that stepping through a bottom context that is not a home context works as expected. Example to reproduce: p := Process forContext: ([[] ensure: []] asContext) priority: 40. p debug. Stepping through the "ensure:" should halt the debugger in the first block, but not inside the #ensure: method. M Process>>stepToHome: =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: Process>>stepToHome: (in category 'changing suspended state') ----- stepToHome: aContext + "Resume self until the home of top context is aContext. Top context may be a block context. Catch any UnhandledErrors that are created while stepping, answering the relevant signalerContext if so. Note that this will cause weird effects if using through to step through UnhandledError code, but as the doctor ordered, don't do that; use over or into instead." - "Resume self until the home of top context is aContext. Top context may be a block context. - Catch any UnhandledErrors that are created while stepping, answering the relevant signalerContext - if so. Note that this will cause weird effects if using through to step through UnhandledError - code, but as the doctor ordered, don't do that; use over or into instead." ^Processor activeProcess evaluate: [| home anError | home := aContext home. [suspendedContext := suspendedContext step. + home == suspendedContext home or: [aContext isDead and: [home isDead]]] whileFalse: - home == suspendedContext home or: [home isDead]] whileFalse: [(suspendedContext selector == #signalForException: and: [(suspendedContext receiver isBehavior and: [ suspendedContext receiver includesBehavior: UnhandledError]) and: [anError := suspendedContext tempAt: 1. ((suspendedContext objectClass: anError) includesBehavior: Exception) and: [anError canSearchForSignalerContext]]]) ifTrue: [anError signalerContext ifNotNil: [:unhandledErrorSignalerContext| [unhandledErrorSignalerContext == suspendedContext] whileFalse: [self completeStep: suspendedContext]. "Give a debugger a chance to update its title to reflect the new exception" Notification new tag: {unhandledErrorSignalerContext. anError}; signal. ^unhandledErrorSignalerContext]]]. suspendedContext] onBehalfOf: self! From Das.Linux at gmx.de Sat Mar 20 18:46:24 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Sat, 20 Mar 2021 19:46:24 +0100 Subject: [squeak-dev] The Inbox: KernelTests-ct.395.mcz In-Reply-To: References: Message-ID: <7E1C6DD7-7F2B-4611-8527-B55309B3867E@gmx.de> > On 20. Mar 2021, at 19:25, Thiede, Christoph wrote: > > Hmm, the diff is broken ... Looked fine in my image. :-( It has two ancestors, tho… -t > > Best, > Christoph > Von: Squeak-dev im Auftrag von commits at source.squeak.org > Gesendet: Samstag, 20. März 2021 19:17:50 > An: squeak-dev at lists.squeakfoundation.org > Betreff: [squeak-dev] The Inbox: KernelTests-ct.395.mcz > > A new version of KernelTests was added to project The Inbox: > http://source.squeak.org/inbox/KernelTests-ct.395.mcz > > ==================== Summary ==================== > > Name: KernelTests-ct.395 > Author: ct > Time: 20 March 2021, 7:17:49.390742 pm > UUID: 76e4d450-32dd-d24c-8aad-68ad212ec955 > Ancestors: KernelTests-mt.394, KernelTests-ct.375 > > Tests simulation of #perform:... primitives 83, 84, and 100. Complements Kernel-ct.1367. Reuploaded to add another fixture for the mirror primitive variant of primitive 100. Corrected order of assertion arguments. > > Replaces KernelTests-ct.38{2,3}, which can be moved into the treated inbox. > > Depends indeed not only on KernelTests-mt.394 but also on KernelTests-ct.375, it would be nice if we could get the latter merged soon, this has already been causing too many merge conflicts in the past. :-) > > =============== Diff against KernelTests-mt.394 =============== > > Item was changed: > SystemOrganization addCategory: #'KernelTests-Classes'! > SystemOrganization addCategory: #'KernelTests-Methods'! > SystemOrganization addCategory: #'KernelTests-Numbers'! > SystemOrganization addCategory: #'KernelTests-Objects'! > SystemOrganization addCategory: #'KernelTests-Processes'! > - SystemOrganization addCategory: #'KernelTests-WriteBarrier'! > - SystemOrganization addCategory: #'KernelTests-Models'! > > Item was changed: > ----- Method: AllocationTest>>testOutOfMemorySignal (in category 'tests') ----- > testOutOfMemorySignal > + "Ensure that OutOfMemory is signaled eventually" > - "Ensure that OutOfMemory is signaled eventually. Restrain the available memory first to not stress the machine too much." > - > | sz | > self setFreeSpaceLimitOf: 1024 * 1024 * 1024 * (Smalltalk wordSize = 8 > ifTrue: [4] > ifFalse: [1.5]) > around: > [sz := 512*1024*1024. "work around the 1GB alloc bug" > + self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory]. > + > + "Call me when this test fails, I want your machine." > + "Current (2017) Spur VMs fail new: & basicNew: with #'bad argument' if given other than a non-negative SmallInteger." > + sz := 1024*1024*1024*1024. > + self should: [Array new: sz] > + raise: OutOfMemory, Error > + withExceptionDo: > + [:ex| > + ex class == Error ifTrue: > + [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! > - self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory].! > > Item was removed: > - ----- Method: AllocationTest>>testOutOfMemorySignalExtreme (in category 'tests') ----- > - testOutOfMemorySignalExtreme > - "Try to allocate a ridiculous amount of memory and check whether the expected error is signaled. Call Eliot when this test fails, he want your machine. :-) > - > - Note that current (2017) Spur VMs fail in #new: and #basicNew: with #'bad argument' if given other than a non-negative SmallInteger. > - > - Also note that this test can be quite stressful to your machine depending on how your operating system allocates the required memory behind the curtains. Better not triggering some robot fetching a tape from somewhere..." > - > - | sz | > - sz := 1024*1024*1024*1024. "= 1 TiB" > - self should: [Array new: sz] > - raise: OutOfMemory, Error > - withExceptionDo: > - [:ex| > - ex class == Error ifTrue: > - [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! > > Item was removed: > - ----- Method: BlockClosureTest>>return: (in category 'private') ----- > - return: something > - > - ^ something! > > Item was removed: > - ----- Method: BlockClosureTest>>testMoreThanOnce (in category 'tests - evaluating') ----- > - testMoreThanOnce > - "Make sure that we can use once more than once" > - | moreThanOnce | > - moreThanOnce := (1 to: 3) collect: [:e | [String new] once -> [Array new] once]. > - self assert: (moreThanOnce allSatisfy: [:each | each key isString]). > - self assert: (moreThanOnce allSatisfy: [:each | each value isArray]). > - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). > - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]).! > > Item was removed: > - ----- Method: BlockClosureTest>>testMoreThanOnceForEqualBlocks (in category 'tests - evaluating') ----- > - testMoreThanOnceForEqualBlocks > - "Make sure that we can use once more than once" > - | moreThanOnce | > - moreThanOnce := (1 to: 3) collect: [:e | [Object new] once -> [Object new] once]. > - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). > - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]). > - self assert: (moreThanOnce noneSatisfy: [:each | each key == each value]).! > > Item was changed: > ----- Method: BlockClosureTest>>testRunSimulated (in category 'tests') ----- > testRunSimulated > + self assert: Rectangle equals: (Context runSimulated: aBlockClosure asContext) class! > - self assert: Rectangle equals: > - (Context runSimulated: aBlockClosure asContext) class. > - self assert: 42 equals: > - (Context runSimulated: [self return: 42]). > - self > - should: [Context runSimulated: [self halt]] > - raise: Halt.! > > Item was removed: > - ----- Method: BlockClosureTest>>testRunSimulatedContextAtEachStep (in category 'tests') ----- > - testRunSimulatedContextAtEachStep > - > - | context | > - context := aBlockClosure asContext. > - self assert: Rectangle equals: (thisContext > - runSimulated: context > - contextAtEachStep: [:ctxt | self assert: > - [ctxt == context or: [ctxt hasSender: context]]]) class.! > > Item was changed: > ----- Method: BlockClosureTest>>testSetUp (in category 'tests') ----- > testSetUp > "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" > self deny: aBlockClosure isContext. > self assert: aBlockClosure isClosure. > self assert: aBlockClosure home = homeOfABlockClosure. > self assert: aBlockClosure receiver = self. > + self assert: aBlockClosure method isCompiledMethod! > - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) > - ifTrue: [aBlockClosure method isCompiledBlock] > - ifFalse: [aBlockClosure method isCompiledMethod])! > > Item was changed: > ----- Method: BlockClosureTest>>testTallyInstructions (in category 'tests') ----- > testTallyInstructions > + self assert: (Context tallyInstructions: aBlockClosure asContext) size = 15! > - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) > - ifTrue: [14] > - ifFalse: [15]) > - equals: (Context tallyInstructions: aBlockClosure asContext) size! > > Item was changed: > ----- Method: ClassTest>>testChangeClassOf (in category 'tests') ----- > testChangeClassOf > "Exercise primitiveChangeClass (primitive 115) for a common use case. This should pass > for any Squeak image format (but failed for image format 68002 prior to VM fix)" > > + self shouldnt: [Inspector new primitiveChangeClassTo: CompiledMethodInspector new] raise: Error! > - self shouldnt: [Exception new primitiveChangeClassTo: Error new] raise: Error! > > Item was changed: > ----- Method: CompiledMethodTest>>testClosureSize (in category 'tests - closures') ----- > testClosureSize > + self > + assert: ((self class >> #withClosure) embeddedBlockClosures at: 1) size > + equals: 2; > + assert: ((self class >> #withClosureNoNLR) embeddedBlockClosures at: 1) size > + equals: 2! > - | compiledMethod expectedSize | > - compiledMethod := (self class >> #withClosure). > - expectedSize := compiledMethod bytecodeSetName > - caseOf: { > - ['SistaV1'] -> [3]. > - ['V3PlusClosures'] -> [2]}. > - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size. > - compiledMethod := (self class >> #withClosureNoNLR). > - expectedSize := compiledMethod bytecodeSetName > - caseOf: { > - ['SistaV1'] -> [3]. > - ['V3PlusClosures'] -> [2]}. > - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size.! > > Item was added: > + TestCase subclass: #ContextTest > + instanceVariableNames: 'aCompiledMethod aReceiver aSender aContext' > + classVariableNames: '' > + poolDictionaries: '' > + category: 'KernelTests-Methods'! > + > + !ContextTest commentStamp: 'ct 1/27/2020 13:03' prior: 0! > + I am an SUnit Test of Context. See also BlockClosureTest. > + See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak seehttp://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ andhttp://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) > + My fixtures are: > + aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" > + aSender - just some arbitrary object, thisContext > + aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". > + aContext - just some arbitray context ... > + > + ! > > Item was added: > + ----- Method: ContextTest>>privRestartTest (in category 'private') ----- > + privRestartTest > + "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" > + |a firstTimeThrough | > + firstTimeThrough := true. > + a := 10. > + > + self assert: 30 equals: [|b| > + self assert: 10 = a . > + self assert: nil == b. > + b := a + 20. > + firstTimeThrough ifTrue: [ > + firstTimeThrough := false. > + thisContext restart.]. > + b] value > + ! > > Item was added: > + ----- Method: ContextTest>>setUp (in category 'running') ----- > + setUp > + super setUp. > + aCompiledMethod := Rectangle methodDict at: #rightCenter. > + aReceiver := 100 at 100 corner: 200 at 200. > + aSender := thisContext. > + aContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! > > Item was added: > + ----- Method: ContextTest>>testActivateReturnValue (in category 'tests') ----- > + testActivateReturnValue > + self assert: (aSender activateReturn: aContext value: #()) isContext. > + self assert: ((aSender activateReturn: aContext value: #()) receiver = aContext).! > > Item was added: > + ----- Method: ContextTest>>testCopyStack (in category 'tests') ----- > + testCopyStack > + self assert: aContext copyStack printString = aContext printString.! > > Item was added: > + ----- Method: ContextTest>>testFindContextSuchThat (in category 'tests') ----- > + testFindContextSuchThat > + self assert: (aContext findContextSuchThat: [:each| true]) printString = aContext printString. > + self assert: (aContext hasContext: aContext). ! > > Item was added: > + ----- Method: ContextTest>>testMethodContext (in category 'tests') ----- > + testMethodContext > + self assert: aContext home notNil. > + self assert: aContext receiver notNil. > + self assert: aContext method isCompiledMethod.! > > Item was added: > + ----- Method: ContextTest>>testMethodIsBottomContext (in category 'tests') ----- > + testMethodIsBottomContext > + self assert: aContext bottomContext = aSender. > + self assert: aContext secondFromBottom = aContext.! > > Item was added: > + ----- Method: ContextTest>>testPrimitive100 (in category 'tests') ----- > + testPrimitive100 > + > + { > + {#isNil. {}. Object}. "valid 0-arg message" > + {#=. {true}. UndefinedObject}. "valid unary message" > + {#ifNil:ifNotNil:. {[2]. [:x | x]}. Object}. "valid binary message" > + {{}. #=. {true}. SequenceableCollection}. "mirror primitive" > + {#isNil}. "missing arguments" > + {#isNil. 'not an array'}. "invalid arguments" > + {#isNil. {}}. "missing lookupClass" > + {#isNil. {'excess arg'}. Object}. "too many arguments" > + {#=. {}. UndefinedObject}. "missing argument" > + {#isNil. {}. Boolean}. "lookupClass not in inheritance chain" > + } do: [:args | > + self > + assert: (nil tryPrimitive: 100 withArgs: args) > + equals: (Context runSimulated: [nil tryPrimitive: 100 withArgs: args])].! > > Item was added: > + ----- Method: ContextTest>>testPrimitive83 (in category 'tests') ----- > + testPrimitive83 > + > + { > + {#isNil}. "valid 0-arg message" > + {#=. true}. "valid unary message" > + {#ifNil:ifNotNil:. [2]. [:x | x]}. "valid binary message" > + {#isNil. 'excess arg'}. "too many arguments" > + {#=}. "missing argument" > + } do: [:args | > + self > + assert: (nil tryPrimitive: 83 withArgs: args) > + equals: (Context runSimulated: [nil tryPrimitive: 83 withArgs: args])].! > > Item was added: > + ----- Method: ContextTest>>testPrimitive84 (in category 'tests') ----- > + testPrimitive84 > + > + { > + {#isNil. {}}. "valid 0-arg message" > + {#=. {true}}. "valid unary message" > + {#ifNil:ifNotNil:. {[2]. [:x | x]}}. "valid binary message" > + {#isNil}. "missing arguments" > + {#isNil. 'not an array'}. "invalid arguments" > + {#isNil. {'excess arg'}}. "too many arguments" > + {#=. {}}. "missing argument" > + } do: [:args | > + self > + assert: (nil tryPrimitive: 84 withArgs: args) > + equals: (Context runSimulated: [nil tryPrimitive: 84 withArgs: args])].! > > Item was added: > + ----- Method: ContextTest>>testRestart (in category 'tests') ----- > + testRestart > + self should: [self privRestartTest] notTakeMoreThan: 0.1 second! > > Item was added: > + ----- Method: ContextTest>>testReturn (in category 'tests') ----- > + testReturn > + "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." > + aContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). > + self assert: (aContext return: 5) = 5! > > Item was added: > + ----- Method: ContextTest>>testSetUp (in category 'tests') ----- > + testSetUp > + "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" > + self assert: aContext isContext. > + self deny: aContext isExecutingBlock. > + self deny: aContext isClosure. > + self deny: aContext isDead. > + "self assert: aMethodContext home = aReceiver." > + "self assert: aMethodContext blockHome = aReceiver." > + self assert: aContext receiver = aReceiver. > + self assert: aContext method isCompiledMethod. > + self assert: aContext method = aCompiledMethod. > + self assert: aContext methodNode selector = #rightCenter. > + self assert: (aContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. > + self assert: aContext client printString = 'ContextTest>>#testSetUp'. > + ! > > Item was removed: > - ----- Method: FloatTest class>>testClassConstantsPasses (in category 'utilities') ----- > - testClassConstantsPasses > - "Answer if testClassConstants passes. This can be used in e.g. the Kernel Package prolog > - to test if Float initialize needs to be run." > - [self new testClassConstants] > - on: TestResult failure > - do: [:ex| ^false]. > - ^true! > > Item was removed: > - ----- Method: FloatTest>>assert:equals:withinUlp: (in category 'asserting') ----- > - assert: expected equals: actual withinUlp: maxUlp > - self assert: (expected - actual) abs <= (maxUlp * expected asFloat ulp)! > > Item was removed: > - ----- Method: FloatTest>>floatLiteralsIn: (in category 'private') ----- > - floatLiteralsIn: method > - | floatLiterals | > - floatLiterals := OrderedCollection new. > - method allLiteralsDo: > - [:lit| lit isFloat ifTrue: [floatLiterals addLast: lit]]. > - ^floatLiterals! > > Item was removed: > - ----- Method: FloatTest>>methodContainsFloatLiteral: (in category 'private') ----- > - methodContainsFloatLiteral: method > - method isQuick ifFalse: > - [method allLiteralsDo: > - [:lit| lit isFloat ifTrue: [^true]]]. > - ^false! > > Item was removed: > - ----- Method: FloatTest>>methodsMaybeContainingBrokenCompiledConstants (in category 'private') ----- > - methodsMaybeContainingBrokenCompiledConstants > - "Answer a set of all methods in the system which contain float constants that differ from those obtaiuned by > - recompiling. These may indicate an old compiler issue, or indeed an issue with the current compiler. This is a > - variant of testCompiledConstants used for collecting the set of methods rather than testing that none exist." > - | identifiedPatients | > - identifiedPatients := IdentitySet new. > - CurrentReadOnlySourceFiles cacheDuring: > - [self systemNavigation allSelectorsAndMethodsDo: > - [:class :selector :method| > - (self methodContainsFloatLiteral: method) ifTrue: > - [| newMethodAndNode newLiterals oldLiterals | > - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. > - newLiterals := self floatLiteralsIn: newMethodAndNode method. > - oldLiterals := self floatLiteralsIn: method. > - "Convenience doit for recompiling broken methods:..." > - "class recompile: selector" > - newLiterals size = oldLiterals size > - ifFalse: [identifiedPatients add: method] > - ifTrue: > - [newLiterals with: oldLiterals do: > - [:new :old| > - (new asIEEE64BitWord = old asIEEE64BitWord > - or: [new isNaN and: old isNaN]) ifFalse: > - [identifiedPatients add: method]]]]]]. > - ^identifiedPatients! > > Item was removed: > - ----- Method: FloatTest>>testClassConstants (in category 'tests - characterization') ----- > - testClassConstants > - > - "Test all the class constants that are floats to check that they are valid. > - Sometimes compiler bugs mean that the initialization method is incorrect, etc" > - | expectedVariables unexpectedVariables "these two are for determining if this test is correct, not its results" > - finiteVariables infiniteVariables nanVariables | > - finiteVariables := #(Pi Halfpi Twopi ThreePi RadiansPerDegree Ln2 Ln10 Sqrt2 E Epsilon MaxVal MaxValLn NegativeZero). > - infiniteVariables := #(Infinity NegativeInfinity). > - nanVariables := #(NaN). > - expectedVariables := Set new. > - unexpectedVariables := Set new. > - Float classPool keysAndValuesDo: > - [:name :value| > - value isFloat > - ifTrue: > - [(finiteVariables includes: name) ifTrue: > - [expectedVariables add: name. > - self assert: value isFinite. > - self deny: value isInfinite. > - self deny: value isNaN]. > - (infiniteVariables includes: name) ifTrue: > - [expectedVariables add: name. > - self deny: value isFinite. > - self assert: value isInfinite. > - self deny: value isNaN]. > - (nanVariables includes: name) ifTrue: > - [expectedVariables add: name. > - self deny: value isFinite. > - self deny: value isInfinite. > - self assert: value isNaN]. > - (expectedVariables includes: name) ifFalse: > - [unexpectedVariables add: name]] > - ifFalse: > - [self deny: ((finiteVariables includes: name) or: [(infiniteVariables includes: name) or: [nanVariables includes: name]])]]. > - "Now check that test itself is working as intended..." > - self assert: unexpectedVariables isEmpty. > - self assert: expectedVariables = (finiteVariables, infiniteVariables, nanVariables) asSet! > > Item was removed: > - ----- Method: FloatTest>>testCloseToFurthestCloseToNeasrest (in category 'tests - compare') ----- > - testCloseToFurthestCloseToNeasrest > - | x nearest furthest | > - x := 1.0e-6. > - nearest := 1.0e-7. > - furthest := 0.0. > - self assert: (x - nearest) abs < (x - furthest) abs. > - self assert: (x closeTo: furthest) ==> (x closeTo: nearest)! > > Item was removed: > - ----- Method: FloatTest>>testCloseToIsSymmetric (in category 'tests - compare') ----- > - testCloseToIsSymmetric > - self assert: ((1<<2000) reciprocal closeTo: 1.0e-6) equals: (1.0e-6 closeTo: (1<<2000) reciprocal)! > > Item was removed: > - ----- Method: FloatTest>>testCompiledConstants (in category 'tests') ----- > - testCompiledConstants > - "Test that any methods containing a floating point literal have been correctly compiled." > - CurrentReadOnlySourceFiles cacheDuring: > - [self systemNavigation allSelectorsAndMethodsDo: > - [:class :selector :method| > - (self methodContainsFloatLiteral: method) ifTrue: > - [| newMethodAndNode newLiterals oldLiterals | > - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. > - newLiterals := self floatLiteralsIn: newMethodAndNode method. > - oldLiterals := self floatLiteralsIn: method. > - "Convenience doit for recompiling broken methods:..." > - "class recompile: selector" > - self assert: newLiterals size = oldLiterals size. > - newLiterals with: oldLiterals do: > - [:new :old| > - self assert: (new asIEEE64BitWord = old asIEEE64BitWord > - or: [new isNaN and: old isNaN])]]]]! > > Item was removed: > - ----- Method: FloatTest>>testLog2near1 (in category 'tests - mathematical functions') ----- > - testLog2near1 > - self assert: 1.0 predecessor ln / 2 ln equals: 1.0 predecessor log2 withinUlp: 2. > - self assert: 1.0 successor ln / 2 ln equals: 1.0 successor log2 withinUlp: 2! > > Item was removed: > - TestCase subclass: #MethodContextTest > - instanceVariableNames: 'aCompiledMethod aReceiver aMethodContext aSender' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-Methods'! > - > - !MethodContextTest commentStamp: 'eem 3/30/2017 17:42' prior: 0! > - I am an SUnit Test of Context. See also BlockClosureTest. > - See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak seehttp://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ andhttp://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) > - My fixtures are: > - aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" > - aSender - just some arbitrary object, thisContext > - aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". > - aMethodContext - just some arbitray context ... > - > - ! > > Item was removed: > - ----- Method: MethodContextTest>>privRestartTest (in category 'private') ----- > - privRestartTest > - "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" > - |a firstTimeThrough | > - firstTimeThrough := true. > - a := 10. > - > - self assert: 30 equals: [|b| > - self assert: 10 = a . > - self assert: nil == b. > - b := a + 20. > - firstTimeThrough ifTrue: [ > - firstTimeThrough := false. > - thisContext restart.]. > - b] value > - ! > > Item was removed: > - ----- Method: MethodContextTest>>setUp (in category 'running') ----- > - setUp > - super setUp. > - aCompiledMethod := Rectangle methodDict at: #rightCenter. > - aReceiver := 100 at 100 corner: 200 at 200. > - aSender := thisContext. > - aMethodContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! > > Item was removed: > - ----- Method: MethodContextTest>>testActivateReturnValue (in category 'tests') ----- > - testActivateReturnValue > - self assert: (aSender activateReturn: aMethodContext value: #()) isContext. > - self assert: ((aSender activateReturn: aMethodContext value: #()) receiver = aMethodContext).! > > Item was removed: > - ----- Method: MethodContextTest>>testCopyStack (in category 'tests') ----- > - testCopyStack > - self assert: aMethodContext copyStack printString = aMethodContext printString.! > > Item was removed: > - ----- Method: MethodContextTest>>testCopyTo (in category 'tests') ----- > - testCopyTo > - > - | context depth targetSender | > - context := thisContext. > - depth := 1. > - targetSender := context. > - [ (targetSender := targetSender sender) isNil ] whileFalse: [ > - | original copy | > - original := context. > - copy := context copyTo: targetSender. > - 1 to: depth do: [ :index | > - index = 1 ifFalse: [ > - "Since we're copying thisContext, the pc and stackPtr may be different for the current frame." > - self > - assert: original pc equals: copy pc; > - assert: original stackPtr equals: copy stackPtr ]. > - self > - deny: original == copy; > - assert: original method equals: copy method; > - assert: original closure equals: copy closure; > - assert: original receiver equals: copy receiver. > - original := original sender. > - copy := copy sender ]. > - self > - assert: copy isNil; > - assert: original == targetSender. > - depth := depth + 1 ]! > > Item was removed: > - ----- Method: MethodContextTest>>testFindContextSuchThat (in category 'tests') ----- > - testFindContextSuchThat > - self assert: (aMethodContext findContextSuchThat: [:each| true]) printString = aMethodContext printString. > - self assert: (aMethodContext hasContext: aMethodContext). ! > > Item was removed: > - ----- Method: MethodContextTest>>testMethodContext (in category 'tests') ----- > - testMethodContext > - self assert: aMethodContext home notNil. > - self assert: aMethodContext receiver notNil. > - self assert: aMethodContext method isCompiledMethod.! > > Item was removed: > - ----- Method: MethodContextTest>>testMethodIsBottomContext (in category 'tests') ----- > - testMethodIsBottomContext > - self assert: aMethodContext bottomContext = aSender. > - self assert: aMethodContext secondFromBottom = aMethodContext.! > > Item was removed: > - ----- Method: MethodContextTest>>testRestart (in category 'tests') ----- > - testRestart > - self should: [self privRestartTest] notTakeMoreThan: 0.1 second! > > Item was removed: > - ----- Method: MethodContextTest>>testReturn (in category 'tests') ----- > - testReturn > - "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." > - aMethodContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). > - self assert: (aMethodContext return: 5) = 5! > > Item was removed: > - ----- Method: MethodContextTest>>testSetUp (in category 'tests') ----- > - testSetUp > - "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" > - self assert: aMethodContext isContext. > - self deny: aMethodContext isExecutingBlock. > - self deny: aMethodContext isClosure. > - self deny: aMethodContext isDead. > - "self assert: aMethodContext home = aReceiver." > - "self assert: aMethodContext blockHome = aReceiver." > - self assert: aMethodContext receiver = aReceiver. > - self assert: aMethodContext method isCompiledMethod. > - self assert: aMethodContext method = aCompiledMethod. > - self assert: aMethodContext methodNode selector = #rightCenter. > - self assert: (aMethodContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. > - self assert: aMethodContext client printString = 'MethodContextTest>>#testSetUp'. > - ! > > Item was removed: > - TestCase subclass: #ModelTest > - instanceVariableNames: '' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-Models'! > > Item was removed: > - ----- Method: ModelTest>>testCopyDependents (in category 'tests') ----- > - testCopyDependents > - > - | bar foo | > - foo := Model new. > - foo addDependent: 42. > - self assert: {42} equals: foo dependents asArray. > - > - bar := foo copy. > - self assert: bar dependents isEmpty.! > > Item was removed: > - ----- Method: NumberTest>>testExactLog2 (in category 'tests') ----- > - testExactLog2 > - -10 to: 10 do: [:i | self assert: i equals: (2 raisedToInteger: i) log2]. > - Float emin - Float precision + 1 to: Float emax do: [:i | self assert: i equals: (1.0 timesTwoPower: i) log2].! > > Item was removed: > - ----- Method: NumberTest>>testLog2doesNotOverflow (in category 'tests') ----- > - testLog2doesNotOverflow > - "Note: though this is not a strict identity, we can use strict Float equality here" > - self assert: 3000.0 equals: ((1 bitShift: 3000) - 1) log2. > - self assert: 1500.0 equals: (((1 bitShift: 3000) - 1) / (1 bitShift: 1500)) log2.! > > Item was removed: > - ----- Method: NumberTest>>testLog2doesNotUnderflow (in category 'tests') ----- > - testLog2doesNotUnderflow > - "Note: though this is not a strict identity, we can use strict Float equality here" > - self assert: -2000.0 equals: ((1 bitShift: 2000) - 1) reciprocal log2! > > Item was removed: > - ----- Method: ObjectTest>>testCopyDependents (in category 'tests') ----- > - testCopyDependents > - > - | bar foo | > - foo := Object new. > - foo addDependent: 42. > - self assert: {42} equals: foo dependents asArray. > - > - bar := foo copy. > - self assert: bar dependents isEmpty.! > > Item was removed: > - ----- Method: ProcessTest>>genuineProcess (in category 'support') ----- > - genuineProcess > - > - "Usually, we don't want to expose this from the class under test." > - ^ Processor instVarNamed: 'genuineProcess'! > > Item was removed: > - ----- Method: ProcessTest>>testEvaluateOnBehalfOf (in category 'tests') ----- > - testEvaluateOnBehalfOf > - > - | p1 p2 sem results | > - self genuineProcess == Processor activeProcess > - ifFalse: [self fail: 'Cannot debug this test']. > - > - sem := Semaphore new. > - p1 := [] newProcess. > - p1 environmentAt: #foo put: 1. > - p2 := [ > - Processor activeProcess environmentAt: #foo put: 2. > - results := { > - Processor activeProcess environmentAt: #foo. > - self genuineProcess environmentAt: #foo. > - Processor activeProcess > - evaluate: [Processor activeProcess environmentAt: #foo] > - onBehalfOf: p1. > - Processor activeProcess > - evaluate: [self genuineProcess environmentAt: #foo] > - onBehalfOf: p1. > - Processor activeProcess environmentAt: #foo }. > - sem signal > - ] newProcess. > - > - p2 resume. > - sem wait. > - > - self assert: {2. 2. 1. 2. 2} equals: results.! > > Item was removed: > - ----- Method: ProcessTest>>testProcessFaithfulRunning (in category 'tests') ----- > - testProcessFaithfulRunning > - "While simulating a process using #runUntilErrorOrReturnFrom:, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." > - > - | process result | > - process := Process forBlock: [ > - result := Processor activeProcess environmentAt: #foo]. > - process environmentAt: #foo put: 42. > - > - process complete: process suspendedContext. > - > - self assert: 42 equals: result.! > > Item was removed: > - ----- Method: ProcessTest>>testProcessFaithfulSimulation (in category 'tests') ----- > - testProcessFaithfulSimulation > - "While simulating a process using the bytecode simulation machinery, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." > - > - | process result | > - process := Process forBlock: [ > - result := Processor activeProcess environmentAt: #foo]. > - process environmentAt: #foo put: 42. > - > - process runUntil: [:context | context isDead]. > - > - self assert: 42 equals: result.! > > Item was removed: > - ----- Method: PromiseTest>>testAnErrorInOnRejectedRejectsPromise (in category 'tests - monad') ----- > - testAnErrorInOnRejectedRejectsPromise > - "https://promisesaplus.com section 2.2.7.2" > - | p q error | > - p := Promise new. > - q := p ifRejected: [:e | (error := KeyNotFound new) signal]. > - p rejectWith: 1. > - self assert: p isRejected description: 'Original Promise not rejected'. > - self assert: q isRejected description: 'Broken Promise not rejected'. > - self assert: p error = 1. > - self assert: q error == error.! > > Item was changed: > ----- Method: PromiseTest>>testAnErrorInThenRejectsPromise (in category 'tests - monad') ----- > testAnErrorInThenRejectsPromise > + | p q | > - "https://promisesaplus.com section 2.2.7.2" > - | p q error | > p := Promise new. > + q := p then: [:v | KeyNotFound signal]. > - q := p then: [:v | (error := KeyNotFound new) signal]. > p resolveWith: 1. > self deny: p isRejected description: 'Original Promise rejected'. > + self assert: q isRejected description: 'Broken Promise not rejected'.! > - self assert: q isRejected description: 'Broken Promise not rejected'. > - self assert: p value = 1. > - self assert: q error == error.! > > Item was removed: > - ----- Method: PromiseTest>>testNilErrBlockPropagation (in category 'tests - monad') ----- > - testNilErrBlockPropagation > - "https://promisesaplus.com section 2.2.7.4" > - | p q | > - p := Promise new. > - q := p then: [:v | self error: 'Shouldn''t call resolvedBlock'] ifRejected: nil. > - p rejectWith: 1. > - self assert: p isRejected. > - self assert: q isRejected. > - self assert: p error equals: 1. > - self assert: q error equals: 1.! > > Item was removed: > - ----- Method: PromiseTest>>testNilResolvedBlockPropagation (in category 'tests - monad') ----- > - testNilResolvedBlockPropagation > - "https://promisesaplus.com section 2.2.7.3" > - | p q | > - p := Promise new. > - q := p then: nil ifRejected: [:e | self error: 'Shouldn''t call errBlock']. > - p resolveWith: 1. > - self assert: p isResolved. > - self assert: q isResolved. > - self assert: p value equals: 1. > - self assert: q value equals: 1.! > > Item was changed: > ----- Method: PromiseTest>>testifRejectedRunsBlockIfPromiseFails (in category 'tests - monad') ----- > testifRejectedRunsBlockIfPromiseFails > - "https://promisesaplus.com section 2.2.7.1" > | p q error | > error := nil. > p := Promise new. > + q := p ifRejected: [:e | error := e]. > - q := p ifRejected: [:e | error := e "N.B. returns a value, does not signal an Exception"]. > p rejectWith: KeyNotFound new. > + self assert: q isRejected. > + self assert: KeyNotFound equals: error class.! > - self assert: q isResolved. > - self assert: KeyNotFound equals: error class. > - self assert: q value == error.! > > Item was removed: > - Object subclass: #WriteBarrierAnotherStub > - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-WriteBarrier'! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var1 (in category 'accessing') ----- > - var1 > - ^ var1! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var10 (in category 'accessing') ----- > - var10 > - ^ var10! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var10: (in category 'accessing') ----- > - var10: anObject > - var10 := anObject! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var1: (in category 'accessing') ----- > - var1: anObject > - var1 := anObject! > > Item was removed: > - Object subclass: #WriteBarrierStub > - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-WriteBarrier'! > > Item was removed: > - ----- Method: WriteBarrierStub>>var1 (in category 'accessing') ----- > - var1 > - ^ var1! > > Item was removed: > - ----- Method: WriteBarrierStub>>var10 (in category 'accessing') ----- > - var10 > - ^ var10! > > Item was removed: > - ----- Method: WriteBarrierStub>>var10: (in category 'accessing') ----- > - var10: anObject > - var10 := anObject! > > Item was removed: > - ----- Method: WriteBarrierStub>>var1: (in category 'accessing') ----- > - var1: anObject > - var1 := anObject! > > Item was removed: > - TestCase subclass: #WriteBarrierTest > - instanceVariableNames: '' > - classVariableNames: 'ContextInstance' > - poolDictionaries: '' > - category: 'KernelTests-WriteBarrier'! > - > - !WriteBarrierTest commentStamp: '' prior: 0! > - My tests ensure the ReadOnly property of objects work properly. > - > - #testMutateIVObject is a good start to understand what is going on. > - > - The VM needs to be compiled with -DIMMUTABILTY= true for those tests to work.! > > Item was removed: > - ----- Method: WriteBarrierTest class>>initialize (in category 'initialization') ----- > - initialize > - > - ContextInstance := Context sender: nil receiver: self new method: self >> #alwaysWritableObjects arguments: #()! > > Item was removed: > - ----- Method: WriteBarrierTest>>alwaysReadOnlyObjects (in category 'guinea pigs') ----- > - alwaysReadOnlyObjects > - "Immediates are always immutable" > - ^ { 1 }! > > Item was removed: > - ----- Method: WriteBarrierTest>>alwaysWritableObjects (in category 'guinea pigs') ----- > - alwaysWritableObjects > - "Objects that currently can't be immutable" > - ^ { ContextInstance . > - Processor . > - Processor activeProcess }! > > Item was removed: > - ----- Method: WriteBarrierTest>>expectedFailures (in category 'expected failures') ----- > - expectedFailures > - Smalltalk supportsReadOnlyObjects ifFalse: > - [^self class testSelectors]. > - ^#( testMutateByteArrayUsingDoubleAtPut testMutateByteArrayUsingFloatAtPut ), > - ((Smalltalk classNamed: #MirrorPrimitives) > - ifNil: [#(testBasicProxyReadOnly testBasicProxyWritable testSetIsReadOnlySuccessProxy)] > - ifNotNil: [#()])! > > Item was removed: > - ----- Method: WriteBarrierTest>>maybeReadOnlyObjects (in category 'guinea pigs') ----- > - maybeReadOnlyObjects > - "ByteObject, Variable object, fixed sized object" > - ^ { { 1 . 2 . 3 } asByteArray . { 1 . 2 . 3 } . (MessageSend receiver: 1 selector: #+ argument: 2) }! > > Item was removed: > - ----- Method: WriteBarrierTest>>testAttemptToMutateLiterals (in category 'tests - object') ----- > - testAttemptToMutateLiterals > - | guineaPigs | > - guineaPigs := {#[1 2 3] . #(1 2 3) }. > - guineaPigs do: > - [ :guineaPig | > - self should: [guineaPig at: 1 put: 4] > - raise: ModificationForbidden]. > - > - self should: [guineaPigs first become: guineaPigs second ] > - raise: ModificationForbidden. > - > - self should: [ByteString adoptInstance: guineaPigs first] > - raise: ModificationForbidden. > - > - self should: [WeakArray adoptInstance: guineaPigs last] > - raise: ModificationForbidden! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicProxyReadOnly (in category 'tests - proxy') ----- > - testBasicProxyReadOnly > - self alwaysReadOnlyObjects do: [ :each | > - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: true ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicProxyWritable (in category 'tests - proxy') ----- > - testBasicProxyWritable > - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | > - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: false ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicReadOnly (in category 'tests - object') ----- > - testBasicReadOnly > - self alwaysReadOnlyObjects do: [ :each | > - self assert: each isReadOnlyObject equals: true ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicWritable (in category 'tests - object') ----- > - testBasicWritable > - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | > - self assert: each isReadOnlyObject equals: false ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBecomeReadOnly (in category 'tests - object') ----- > - testBecomeReadOnly > - | readOnlyArrays readOnlyByteArrays | > - readOnlyArrays := (1 to: 3) collect: [:n| (0 to: n) asArray beReadOnlyObject; yourself]. > - "N.B. if the targets are read-only this fails, which is correct for elementsForwardIdentityTo: since copyHash is implicitly true; > - we need to write a test for a putative elementsForwardIdentityNoCopyHashTo:" > - readOnlyByteArrays := (1 to: 3) collect: [:n| (0 to: n) asByteArray" beReadOnlyObject; yourself"]. > - self should: [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] > - raise: ModificationForbidden. > - [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] > - on: ModificationForbidden > - do: [:ex| > - false > - ifTrue: "This fails, but should succeed. I *think* it's to do with catching signals when resignalling" > - [(ex mirror detect: [:element| element isReadOnlyObject] ifNone: []) ifNotNil: > - [:readOnlyObj| readOnlyObj beWritableObject]] > - ifFalse: > - [ex mirror do: [:element| element beWritableObject]]. > - ex retryModification]. > - self assert: (readOnlyArrays allSatisfy: [:array| array class == ByteArray])! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingByteAtPut (in category 'tests - object') ----- > - testMutateByteArrayUsingByteAtPut > - | guineaPig | > - guineaPig := ByteArray new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig byteAt: 1 put: 12 ] > - raise: ModificationForbidden. > - > - [ guineaPig byteAt: 1 put: 12 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: 12. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - self > - should: [ guineaPig byteAt: 1 put: 13 ] > - raise: ModificationForbidden. > - > - [ guineaPig byteAt: 1 put: 13 ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig first equals: 13. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingDoubleAtPut (in category 'tests - object') ----- > - testMutateByteArrayUsingDoubleAtPut > - | guineaPig | > - guineaPig := ByteArray new: 8. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] > - raise: ModificationForbidden. > - > - [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: (2 raisedTo: 65) asFloat. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - self > - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] > - raise: ModificationForbidden. > - > - [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig first equals: (2 raisedTo: 64) asFloat. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingFloatAtPut (in category 'tests - object') ----- > - testMutateByteArrayUsingFloatAtPut > - | guineaPig | > - guineaPig := ByteArray new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig floatAt: 1 put: 1.0 ] > - raise: ModificationForbidden. > - > - [ guineaPig floatAt: 1 put: 1.0 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: 1.0. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig floatAt: 1 put: 2.0 ] > - raise: ModificationForbidden. > - > - [ guineaPig floatAt: 1 put: 2.0 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig first equals: 2.0. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingAtPut (in category 'tests - object') ----- > - testMutateByteStringyUsingAtPut > - | guineaPig | > - guineaPig := ByteString new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: $h ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: $h ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: $h. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: $g ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: $g ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume ]. > - > - self assert: guineaPig first equals: $g. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingByteAtPut (in category 'tests - object') ----- > - testMutateByteStringyUsingByteAtPut > - | guineaPig | > - guineaPig := ByteString new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig byteAt: 1 put: 100 ] > - raise: ModificationForbidden. > - > - [ guineaPig byteAt: 1 put: 100 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first asciiValue equals: 100! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteSymbolUsingPrivateAtPut (in category 'tests - object') ----- > - testMutateByteSymbolUsingPrivateAtPut > - | guineaPig | > - [guineaPig := #hello. > - guineaPig beReadOnlyObject. > - > - self > - should: ((guineaPig class includesSelector: #pvtAt:put:) > - ifTrue: [[ guineaPig perform: #pvtAt:put: with: 1 with: $q ]] "Squeak refuses to compile non-self sends of pvt* selectors." > - ifFalse: [[ guineaPig privateAt: 1 put: $q ]]) > - raise: ModificationForbidden ] > - ensure: > - [ guineaPig beWritableObject ]. > - > - self assert: guineaPig first equals: $h! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateIVObject (in category 'tests - object') ----- > - testMutateIVObject > - | guineaPig | > - guineaPig := MessageSend new. > - guineaPig beReadOnlyObject. > - [ guineaPig receiver: 1 ] > - on: ModificationForbidden > - do: [ :modification | "Surely a NoModification error" ]. > - guineaPig > - beWritableObject; > - selector: #+; > - beReadOnlyObject. > - [ guineaPig arguments: #(2) ] > - on: ModificationForbidden > - do: [ :modification |"Surely a NoModification error" ]. > - self assert: guineaPig receiver isNil. > - self assert: guineaPig arguments isNil. > - self assert: guineaPig selector == #+.! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectClass (in category 'tests - object') ----- > - testMutateObjectClass > - | guineaPig | > - guineaPig := WriteBarrierStub new. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] > - raise: ModificationForbidden. > - > - [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig class equals: WriteBarrierAnotherStub! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectClassViaAdoption (in category 'tests - object') ----- > - testMutateObjectClassViaAdoption > - | guineaPig | > - guineaPig := WriteBarrierStub new. > - guineaPig beReadOnlyObject. > - > - self > - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - raise: ModificationForbidden. > - > - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig class equals: WriteBarrierAnotherStub. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - self > - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - raise: ModificationForbidden. > - > - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig class equals: WriteBarrierAnotherStub. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectFirstInstVarWithManyVars (in category 'tests - object') ----- > - testMutateObjectFirstInstVarWithManyVars > - | guineaPig failure | > - guineaPig := WriteBarrierStub new. > - guineaPig beReadOnlyObject. > - failure := [ guineaPig var1: #test ] on: ModificationForbidden do: [:err | err]. > - > - self assert: failure fieldIndex equals: 1! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectInstVarShouldCatchRightFailure (in category 'tests - object') ----- > - testMutateObjectInstVarShouldCatchRightFailure > - | guineaPig failure | > - guineaPig := MessageSend new. > - guineaPig beReadOnlyObject. > - failure := [ guineaPig receiver: #test ] on: ModificationForbidden do: [:err | err]. > - > - self assert: failure object == guineaPig. > - self assert: failure newValue equals: #test. > - self assert: failure fieldIndex equals: 1.! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingAtPut (in category 'tests - object') ----- > - testMutateObjectInstVarUsingAtPut > - | guineaPig | > - guineaPig := Array new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: #test ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: #test ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: #test. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: #test ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: #test ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume ]. > - > - self assert: guineaPig first equals: #test. > - self assert: guineaPig isReadOnlyObject > - ! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingBasicAtPut (in category 'tests - object') --- From Christoph.Thiede at student.hpi.uni-potsdam.de Sat Mar 20 18:53:50 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sat, 20 Mar 2021 18:53:50 +0000 Subject: [squeak-dev] The Inbox: KernelTests-ct.395.mcz In-Reply-To: <7E1C6DD7-7F2B-4611-8527-B55309B3867E@gmx.de> References: , <7E1C6DD7-7F2B-4611-8527-B55309B3867E@gmx.de> Message-ID: <906d545da4da47ee9fc7a9f628488a6f@student.hpi.uni-potsdam.de> I mentioned this in the description. I am carrying this dependency around for some time. Nevertheless, in the past, two-ancestor diff worked well, see Kernel-ct.382. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Tobias Pape Gesendet: Samstag, 20. März 2021 19:46:24 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] The Inbox: KernelTests-ct.395.mcz > On 20. Mar 2021, at 19:25, Thiede, Christoph wrote: > > Hmm, the diff is broken ... Looked fine in my image. :-( It has two ancestors, tho… -t > > Best, > Christoph > Von: Squeak-dev im Auftrag von commits at source.squeak.org > Gesendet: Samstag, 20. März 2021 19:17:50 > An: squeak-dev at lists.squeakfoundation.org > Betreff: [squeak-dev] The Inbox: KernelTests-ct.395.mcz > > A new version of KernelTests was added to project The Inbox: > http://source.squeak.org/inbox/KernelTests-ct.395.mcz > > ==================== Summary ==================== > > Name: KernelTests-ct.395 > Author: ct > Time: 20 March 2021, 7:17:49.390742 pm > UUID: 76e4d450-32dd-d24c-8aad-68ad212ec955 > Ancestors: KernelTests-mt.394, KernelTests-ct.375 > > Tests simulation of #perform:... primitives 83, 84, and 100. Complements Kernel-ct.1367. Reuploaded to add another fixture for the mirror primitive variant of primitive 100. Corrected order of assertion arguments. > > Replaces KernelTests-ct.38{2,3}, which can be moved into the treated inbox. > > Depends indeed not only on KernelTests-mt.394 but also on KernelTests-ct.375, it would be nice if we could get the latter merged soon, this has already been causing too many merge conflicts in the past. :-) > > =============== Diff against KernelTests-mt.394 =============== > > Item was changed: > SystemOrganization addCategory: #'KernelTests-Classes'! > SystemOrganization addCategory: #'KernelTests-Methods'! > SystemOrganization addCategory: #'KernelTests-Numbers'! > SystemOrganization addCategory: #'KernelTests-Objects'! > SystemOrganization addCategory: #'KernelTests-Processes'! > - SystemOrganization addCategory: #'KernelTests-WriteBarrier'! > - SystemOrganization addCategory: #'KernelTests-Models'! > > Item was changed: > ----- Method: AllocationTest>>testOutOfMemorySignal (in category 'tests') ----- > testOutOfMemorySignal > + "Ensure that OutOfMemory is signaled eventually" > - "Ensure that OutOfMemory is signaled eventually. Restrain the available memory first to not stress the machine too much." > - > | sz | > self setFreeSpaceLimitOf: 1024 * 1024 * 1024 * (Smalltalk wordSize = 8 > ifTrue: [4] > ifFalse: [1.5]) > around: > [sz := 512*1024*1024. "work around the 1GB alloc bug" > + self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory]. > + > + "Call me when this test fails, I want your machine." > + "Current (2017) Spur VMs fail new: & basicNew: with #'bad argument' if given other than a non-negative SmallInteger." > + sz := 1024*1024*1024*1024. > + self should: [Array new: sz] > + raise: OutOfMemory, Error > + withExceptionDo: > + [:ex| > + ex class == Error ifTrue: > + [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! > - self should: [(1 to: 2000) collect: [:i| Array new: sz]] raise: OutOfMemory].! > > Item was removed: > - ----- Method: AllocationTest>>testOutOfMemorySignalExtreme (in category 'tests') ----- > - testOutOfMemorySignalExtreme > - "Try to allocate a ridiculous amount of memory and check whether the expected error is signaled. Call Eliot when this test fails, he want your machine. :-) > - > - Note that current (2017) Spur VMs fail in #new: and #basicNew: with #'bad argument' if given other than a non-negative SmallInteger. > - > - Also note that this test can be quite stressful to your machine depending on how your operating system allocates the required memory behind the curtains. Better not triggering some robot fetching a tape from somewhere..." > - > - | sz | > - sz := 1024*1024*1024*1024. "= 1 TiB" > - self should: [Array new: sz] > - raise: OutOfMemory, Error > - withExceptionDo: > - [:ex| > - ex class == Error ifTrue: > - [self assert: [ex messageText includesSubstring: 'basicNew: with invalid argument']]]! > > Item was removed: > - ----- Method: BlockClosureTest>>return: (in category 'private') ----- > - return: something > - > - ^ something! > > Item was removed: > - ----- Method: BlockClosureTest>>testMoreThanOnce (in category 'tests - evaluating') ----- > - testMoreThanOnce > - "Make sure that we can use once more than once" > - | moreThanOnce | > - moreThanOnce := (1 to: 3) collect: [:e | [String new] once -> [Array new] once]. > - self assert: (moreThanOnce allSatisfy: [:each | each key isString]). > - self assert: (moreThanOnce allSatisfy: [:each | each value isArray]). > - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). > - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]).! > > Item was removed: > - ----- Method: BlockClosureTest>>testMoreThanOnceForEqualBlocks (in category 'tests - evaluating') ----- > - testMoreThanOnceForEqualBlocks > - "Make sure that we can use once more than once" > - | moreThanOnce | > - moreThanOnce := (1 to: 3) collect: [:e | [Object new] once -> [Object new] once]. > - self assert: (moreThanOnce allSatisfy: [:each | each key == moreThanOnce first key]). > - self assert: (moreThanOnce allSatisfy: [:each | each value == moreThanOnce first value]). > - self assert: (moreThanOnce noneSatisfy: [:each | each key == each value]).! > > Item was changed: > ----- Method: BlockClosureTest>>testRunSimulated (in category 'tests') ----- > testRunSimulated > + self assert: Rectangle equals: (Context runSimulated: aBlockClosure asContext) class! > - self assert: Rectangle equals: > - (Context runSimulated: aBlockClosure asContext) class. > - self assert: 42 equals: > - (Context runSimulated: [self return: 42]). > - self > - should: [Context runSimulated: [self halt]] > - raise: Halt.! > > Item was removed: > - ----- Method: BlockClosureTest>>testRunSimulatedContextAtEachStep (in category 'tests') ----- > - testRunSimulatedContextAtEachStep > - > - | context | > - context := aBlockClosure asContext. > - self assert: Rectangle equals: (thisContext > - runSimulated: context > - contextAtEachStep: [:ctxt | self assert: > - [ctxt == context or: [ctxt hasSender: context]]]) class.! > > Item was changed: > ----- Method: BlockClosureTest>>testSetUp (in category 'tests') ----- > testSetUp > "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" > self deny: aBlockClosure isContext. > self assert: aBlockClosure isClosure. > self assert: aBlockClosure home = homeOfABlockClosure. > self assert: aBlockClosure receiver = self. > + self assert: aBlockClosure method isCompiledMethod! > - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) > - ifTrue: [aBlockClosure method isCompiledBlock] > - ifFalse: [aBlockClosure method isCompiledMethod])! > > Item was changed: > ----- Method: BlockClosureTest>>testTallyInstructions (in category 'tests') ----- > testTallyInstructions > + self assert: (Context tallyInstructions: aBlockClosure asContext) size = 15! > - self assert: ((aBlockClosure isMemberOf: FullBlockClosure) > - ifTrue: [14] > - ifFalse: [15]) > - equals: (Context tallyInstructions: aBlockClosure asContext) size! > > Item was changed: > ----- Method: ClassTest>>testChangeClassOf (in category 'tests') ----- > testChangeClassOf > "Exercise primitiveChangeClass (primitive 115) for a common use case. This should pass > for any Squeak image format (but failed for image format 68002 prior to VM fix)" > > + self shouldnt: [Inspector new primitiveChangeClassTo: CompiledMethodInspector new] raise: Error! > - self shouldnt: [Exception new primitiveChangeClassTo: Error new] raise: Error! > > Item was changed: > ----- Method: CompiledMethodTest>>testClosureSize (in category 'tests - closures') ----- > testClosureSize > + self > + assert: ((self class >> #withClosure) embeddedBlockClosures at: 1) size > + equals: 2; > + assert: ((self class >> #withClosureNoNLR) embeddedBlockClosures at: 1) size > + equals: 2! > - | compiledMethod expectedSize | > - compiledMethod := (self class >> #withClosure). > - expectedSize := compiledMethod bytecodeSetName > - caseOf: { > - ['SistaV1'] -> [3]. > - ['V3PlusClosures'] -> [2]}. > - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size. > - compiledMethod := (self class >> #withClosureNoNLR). > - expectedSize := compiledMethod bytecodeSetName > - caseOf: { > - ['SistaV1'] -> [3]. > - ['V3PlusClosures'] -> [2]}. > - self assert: expectedSize equals: (compiledMethod embeddedBlockClosures at: 1) size.! > > Item was added: > + TestCase subclass: #ContextTest > + instanceVariableNames: 'aCompiledMethod aReceiver aSender aContext' > + classVariableNames: '' > + poolDictionaries: '' > + category: 'KernelTests-Methods'! > + > + !ContextTest commentStamp: 'ct 1/27/2020 13:03' prior: 0! > + I am an SUnit Test of Context. See also BlockClosureTest. > + See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak seehttp://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ andhttp://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) > + My fixtures are: > + aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" > + aSender - just some arbitrary object, thisContext > + aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". > + aContext - just some arbitray context ... > + > + ! > > Item was added: > + ----- Method: ContextTest>>privRestartTest (in category 'private') ----- > + privRestartTest > + "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" > + |a firstTimeThrough | > + firstTimeThrough := true. > + a := 10. > + > + self assert: 30 equals: [|b| > + self assert: 10 = a . > + self assert: nil == b. > + b := a + 20. > + firstTimeThrough ifTrue: [ > + firstTimeThrough := false. > + thisContext restart.]. > + b] value > + ! > > Item was added: > + ----- Method: ContextTest>>setUp (in category 'running') ----- > + setUp > + super setUp. > + aCompiledMethod := Rectangle methodDict at: #rightCenter. > + aReceiver := 100 at 100 corner: 200 at 200. > + aSender := thisContext. > + aContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! > > Item was added: > + ----- Method: ContextTest>>testActivateReturnValue (in category 'tests') ----- > + testActivateReturnValue > + self assert: (aSender activateReturn: aContext value: #()) isContext. > + self assert: ((aSender activateReturn: aContext value: #()) receiver = aContext).! > > Item was added: > + ----- Method: ContextTest>>testCopyStack (in category 'tests') ----- > + testCopyStack > + self assert: aContext copyStack printString = aContext printString.! > > Item was added: > + ----- Method: ContextTest>>testFindContextSuchThat (in category 'tests') ----- > + testFindContextSuchThat > + self assert: (aContext findContextSuchThat: [:each| true]) printString = aContext printString. > + self assert: (aContext hasContext: aContext). ! > > Item was added: > + ----- Method: ContextTest>>testMethodContext (in category 'tests') ----- > + testMethodContext > + self assert: aContext home notNil. > + self assert: aContext receiver notNil. > + self assert: aContext method isCompiledMethod.! > > Item was added: > + ----- Method: ContextTest>>testMethodIsBottomContext (in category 'tests') ----- > + testMethodIsBottomContext > + self assert: aContext bottomContext = aSender. > + self assert: aContext secondFromBottom = aContext.! > > Item was added: > + ----- Method: ContextTest>>testPrimitive100 (in category 'tests') ----- > + testPrimitive100 > + > + { > + {#isNil. {}. Object}. "valid 0-arg message" > + {#=. {true}. UndefinedObject}. "valid unary message" > + {#ifNil:ifNotNil:. {[2]. [:x | x]}. Object}. "valid binary message" > + {{}. #=. {true}. SequenceableCollection}. "mirror primitive" > + {#isNil}. "missing arguments" > + {#isNil. 'not an array'}. "invalid arguments" > + {#isNil. {}}. "missing lookupClass" > + {#isNil. {'excess arg'}. Object}. "too many arguments" > + {#=. {}. UndefinedObject}. "missing argument" > + {#isNil. {}. Boolean}. "lookupClass not in inheritance chain" > + } do: [:args | > + self > + assert: (nil tryPrimitive: 100 withArgs: args) > + equals: (Context runSimulated: [nil tryPrimitive: 100 withArgs: args])].! > > Item was added: > + ----- Method: ContextTest>>testPrimitive83 (in category 'tests') ----- > + testPrimitive83 > + > + { > + {#isNil}. "valid 0-arg message" > + {#=. true}. "valid unary message" > + {#ifNil:ifNotNil:. [2]. [:x | x]}. "valid binary message" > + {#isNil. 'excess arg'}. "too many arguments" > + {#=}. "missing argument" > + } do: [:args | > + self > + assert: (nil tryPrimitive: 83 withArgs: args) > + equals: (Context runSimulated: [nil tryPrimitive: 83 withArgs: args])].! > > Item was added: > + ----- Method: ContextTest>>testPrimitive84 (in category 'tests') ----- > + testPrimitive84 > + > + { > + {#isNil. {}}. "valid 0-arg message" > + {#=. {true}}. "valid unary message" > + {#ifNil:ifNotNil:. {[2]. [:x | x]}}. "valid binary message" > + {#isNil}. "missing arguments" > + {#isNil. 'not an array'}. "invalid arguments" > + {#isNil. {'excess arg'}}. "too many arguments" > + {#=. {}}. "missing argument" > + } do: [:args | > + self > + assert: (nil tryPrimitive: 84 withArgs: args) > + equals: (Context runSimulated: [nil tryPrimitive: 84 withArgs: args])].! > > Item was added: > + ----- Method: ContextTest>>testRestart (in category 'tests') ----- > + testRestart > + self should: [self privRestartTest] notTakeMoreThan: 0.1 second! > > Item was added: > + ----- Method: ContextTest>>testReturn (in category 'tests') ----- > + testReturn > + "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." > + aContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). > + self assert: (aContext return: 5) = 5! > > Item was added: > + ----- Method: ContextTest>>testSetUp (in category 'tests') ----- > + testSetUp > + "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" > + self assert: aContext isContext. > + self deny: aContext isExecutingBlock. > + self deny: aContext isClosure. > + self deny: aContext isDead. > + "self assert: aMethodContext home = aReceiver." > + "self assert: aMethodContext blockHome = aReceiver." > + self assert: aContext receiver = aReceiver. > + self assert: aContext method isCompiledMethod. > + self assert: aContext method = aCompiledMethod. > + self assert: aContext methodNode selector = #rightCenter. > + self assert: (aContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. > + self assert: aContext client printString = 'ContextTest>>#testSetUp'. > + ! > > Item was removed: > - ----- Method: FloatTest class>>testClassConstantsPasses (in category 'utilities') ----- > - testClassConstantsPasses > - "Answer if testClassConstants passes. This can be used in e.g. the Kernel Package prolog > - to test if Float initialize needs to be run." > - [self new testClassConstants] > - on: TestResult failure > - do: [:ex| ^false]. > - ^true! > > Item was removed: > - ----- Method: FloatTest>>assert:equals:withinUlp: (in category 'asserting') ----- > - assert: expected equals: actual withinUlp: maxUlp > - self assert: (expected - actual) abs <= (maxUlp * expected asFloat ulp)! > > Item was removed: > - ----- Method: FloatTest>>floatLiteralsIn: (in category 'private') ----- > - floatLiteralsIn: method > - | floatLiterals | > - floatLiterals := OrderedCollection new. > - method allLiteralsDo: > - [:lit| lit isFloat ifTrue: [floatLiterals addLast: lit]]. > - ^floatLiterals! > > Item was removed: > - ----- Method: FloatTest>>methodContainsFloatLiteral: (in category 'private') ----- > - methodContainsFloatLiteral: method > - method isQuick ifFalse: > - [method allLiteralsDo: > - [:lit| lit isFloat ifTrue: [^true]]]. > - ^false! > > Item was removed: > - ----- Method: FloatTest>>methodsMaybeContainingBrokenCompiledConstants (in category 'private') ----- > - methodsMaybeContainingBrokenCompiledConstants > - "Answer a set of all methods in the system which contain float constants that differ from those obtaiuned by > - recompiling. These may indicate an old compiler issue, or indeed an issue with the current compiler. This is a > - variant of testCompiledConstants used for collecting the set of methods rather than testing that none exist." > - | identifiedPatients | > - identifiedPatients := IdentitySet new. > - CurrentReadOnlySourceFiles cacheDuring: > - [self systemNavigation allSelectorsAndMethodsDo: > - [:class :selector :method| > - (self methodContainsFloatLiteral: method) ifTrue: > - [| newMethodAndNode newLiterals oldLiterals | > - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. > - newLiterals := self floatLiteralsIn: newMethodAndNode method. > - oldLiterals := self floatLiteralsIn: method. > - "Convenience doit for recompiling broken methods:..." > - "class recompile: selector" > - newLiterals size = oldLiterals size > - ifFalse: [identifiedPatients add: method] > - ifTrue: > - [newLiterals with: oldLiterals do: > - [:new :old| > - (new asIEEE64BitWord = old asIEEE64BitWord > - or: [new isNaN and: old isNaN]) ifFalse: > - [identifiedPatients add: method]]]]]]. > - ^identifiedPatients! > > Item was removed: > - ----- Method: FloatTest>>testClassConstants (in category 'tests - characterization') ----- > - testClassConstants > - > - "Test all the class constants that are floats to check that they are valid. > - Sometimes compiler bugs mean that the initialization method is incorrect, etc" > - | expectedVariables unexpectedVariables "these two are for determining if this test is correct, not its results" > - finiteVariables infiniteVariables nanVariables | > - finiteVariables := #(Pi Halfpi Twopi ThreePi RadiansPerDegree Ln2 Ln10 Sqrt2 E Epsilon MaxVal MaxValLn NegativeZero). > - infiniteVariables := #(Infinity NegativeInfinity). > - nanVariables := #(NaN). > - expectedVariables := Set new. > - unexpectedVariables := Set new. > - Float classPool keysAndValuesDo: > - [:name :value| > - value isFloat > - ifTrue: > - [(finiteVariables includes: name) ifTrue: > - [expectedVariables add: name. > - self assert: value isFinite. > - self deny: value isInfinite. > - self deny: value isNaN]. > - (infiniteVariables includes: name) ifTrue: > - [expectedVariables add: name. > - self deny: value isFinite. > - self assert: value isInfinite. > - self deny: value isNaN]. > - (nanVariables includes: name) ifTrue: > - [expectedVariables add: name. > - self deny: value isFinite. > - self deny: value isInfinite. > - self assert: value isNaN]. > - (expectedVariables includes: name) ifFalse: > - [unexpectedVariables add: name]] > - ifFalse: > - [self deny: ((finiteVariables includes: name) or: [(infiniteVariables includes: name) or: [nanVariables includes: name]])]]. > - "Now check that test itself is working as intended..." > - self assert: unexpectedVariables isEmpty. > - self assert: expectedVariables = (finiteVariables, infiniteVariables, nanVariables) asSet! > > Item was removed: > - ----- Method: FloatTest>>testCloseToFurthestCloseToNeasrest (in category 'tests - compare') ----- > - testCloseToFurthestCloseToNeasrest > - | x nearest furthest | > - x := 1.0e-6. > - nearest := 1.0e-7. > - furthest := 0.0. > - self assert: (x - nearest) abs < (x - furthest) abs. > - self assert: (x closeTo: furthest) ==> (x closeTo: nearest)! > > Item was removed: > - ----- Method: FloatTest>>testCloseToIsSymmetric (in category 'tests - compare') ----- > - testCloseToIsSymmetric > - self assert: ((1<<2000) reciprocal closeTo: 1.0e-6) equals: (1.0e-6 closeTo: (1<<2000) reciprocal)! > > Item was removed: > - ----- Method: FloatTest>>testCompiledConstants (in category 'tests') ----- > - testCompiledConstants > - "Test that any methods containing a floating point literal have been correctly compiled." > - CurrentReadOnlySourceFiles cacheDuring: > - [self systemNavigation allSelectorsAndMethodsDo: > - [:class :selector :method| > - (self methodContainsFloatLiteral: method) ifTrue: > - [| newMethodAndNode newLiterals oldLiterals | > - newMethodAndNode := class compile: method getSource asString notifying: nil trailer: CompiledMethodTrailer empty ifFail: nil. > - newLiterals := self floatLiteralsIn: newMethodAndNode method. > - oldLiterals := self floatLiteralsIn: method. > - "Convenience doit for recompiling broken methods:..." > - "class recompile: selector" > - self assert: newLiterals size = oldLiterals size. > - newLiterals with: oldLiterals do: > - [:new :old| > - self assert: (new asIEEE64BitWord = old asIEEE64BitWord > - or: [new isNaN and: old isNaN])]]]]! > > Item was removed: > - ----- Method: FloatTest>>testLog2near1 (in category 'tests - mathematical functions') ----- > - testLog2near1 > - self assert: 1.0 predecessor ln / 2 ln equals: 1.0 predecessor log2 withinUlp: 2. > - self assert: 1.0 successor ln / 2 ln equals: 1.0 successor log2 withinUlp: 2! > > Item was removed: > - TestCase subclass: #MethodContextTest > - instanceVariableNames: 'aCompiledMethod aReceiver aMethodContext aSender' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-Methods'! > - > - !MethodContextTest commentStamp: 'eem 3/30/2017 17:42' prior: 0! > - I am an SUnit Test of Context. See also BlockClosureTest. > - See pages 430-437 of A. Goldberg and D. Robson's Smalltalk-80 The Language (aka the purple book), which deal with Contexts. My fixtures are from their example. To see how blocks are implemented in this version of Squeak seehttp://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ andhttp://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/. (The Squeak V3 byte codes are not quite the same as Smalltalk-80, and the SistaV1 byetcodes are quite different.) > - My fixtures are: > - aReceiver - just some arbitrary object, "Rectangle origin: 100 at 100 corner: 200 at 200" > - aSender - just some arbitrary object, thisContext > - aCompiledMethod - just some arbitrary method, "Rectangle rightCenter". > - aMethodContext - just some arbitray context ... > - > - ! > > Item was removed: > - ----- Method: MethodContextTest>>privRestartTest (in category 'private') ----- > - privRestartTest > - "This tests may loop endlessly if incorrect, so call it from another method testing it does not time out" > - |a firstTimeThrough | > - firstTimeThrough := true. > - a := 10. > - > - self assert: 30 equals: [|b| > - self assert: 10 = a . > - self assert: nil == b. > - b := a + 20. > - firstTimeThrough ifTrue: [ > - firstTimeThrough := false. > - thisContext restart.]. > - b] value > - ! > > Item was removed: > - ----- Method: MethodContextTest>>setUp (in category 'running') ----- > - setUp > - super setUp. > - aCompiledMethod := Rectangle methodDict at: #rightCenter. > - aReceiver := 100 at 100 corner: 200 at 200. > - aSender := thisContext. > - aMethodContext := Context sender: aSender receiver: aReceiver method: aCompiledMethod arguments: #(). ! > > Item was removed: > - ----- Method: MethodContextTest>>testActivateReturnValue (in category 'tests') ----- > - testActivateReturnValue > - self assert: (aSender activateReturn: aMethodContext value: #()) isContext. > - self assert: ((aSender activateReturn: aMethodContext value: #()) receiver = aMethodContext).! > > Item was removed: > - ----- Method: MethodContextTest>>testCopyStack (in category 'tests') ----- > - testCopyStack > - self assert: aMethodContext copyStack printString = aMethodContext printString.! > > Item was removed: > - ----- Method: MethodContextTest>>testCopyTo (in category 'tests') ----- > - testCopyTo > - > - | context depth targetSender | > - context := thisContext. > - depth := 1. > - targetSender := context. > - [ (targetSender := targetSender sender) isNil ] whileFalse: [ > - | original copy | > - original := context. > - copy := context copyTo: targetSender. > - 1 to: depth do: [ :index | > - index = 1 ifFalse: [ > - "Since we're copying thisContext, the pc and stackPtr may be different for the current frame." > - self > - assert: original pc equals: copy pc; > - assert: original stackPtr equals: copy stackPtr ]. > - self > - deny: original == copy; > - assert: original method equals: copy method; > - assert: original closure equals: copy closure; > - assert: original receiver equals: copy receiver. > - original := original sender. > - copy := copy sender ]. > - self > - assert: copy isNil; > - assert: original == targetSender. > - depth := depth + 1 ]! > > Item was removed: > - ----- Method: MethodContextTest>>testFindContextSuchThat (in category 'tests') ----- > - testFindContextSuchThat > - self assert: (aMethodContext findContextSuchThat: [:each| true]) printString = aMethodContext printString. > - self assert: (aMethodContext hasContext: aMethodContext). ! > > Item was removed: > - ----- Method: MethodContextTest>>testMethodContext (in category 'tests') ----- > - testMethodContext > - self assert: aMethodContext home notNil. > - self assert: aMethodContext receiver notNil. > - self assert: aMethodContext method isCompiledMethod.! > > Item was removed: > - ----- Method: MethodContextTest>>testMethodIsBottomContext (in category 'tests') ----- > - testMethodIsBottomContext > - self assert: aMethodContext bottomContext = aSender. > - self assert: aMethodContext secondFromBottom = aMethodContext.! > > Item was removed: > - ----- Method: MethodContextTest>>testRestart (in category 'tests') ----- > - testRestart > - self should: [self privRestartTest] notTakeMoreThan: 0.1 second! > > Item was removed: > - ----- Method: MethodContextTest>>testReturn (in category 'tests') ----- > - testReturn > - "Why am I overriding setUp? Because sender must be thisContext, i.e, testReturn, not setUp." > - aMethodContext := Context sender: thisContext receiver: aReceiver method: aCompiledMethod arguments: #(). > - self assert: (aMethodContext return: 5) = 5! > > Item was removed: > - ----- Method: MethodContextTest>>testSetUp (in category 'tests') ----- > - testSetUp > - "Note: In addition to verifying that the setUp worked the way it was expected to, testSetUp is used to illustrate the meaning of the simple access methods, methods that are not normally otherwise 'tested'" > - self assert: aMethodContext isContext. > - self deny: aMethodContext isExecutingBlock. > - self deny: aMethodContext isClosure. > - self deny: aMethodContext isDead. > - "self assert: aMethodContext home = aReceiver." > - "self assert: aMethodContext blockHome = aReceiver." > - self assert: aMethodContext receiver = aReceiver. > - self assert: aMethodContext method isCompiledMethod. > - self assert: aMethodContext method = aCompiledMethod. > - self assert: aMethodContext methodNode selector = #rightCenter. > - self assert: (aMethodContext methodNodeFormattedAndDecorated: true) selector = #rightCenter. > - self assert: aMethodContext client printString = 'MethodContextTest>>#testSetUp'. > - ! > > Item was removed: > - TestCase subclass: #ModelTest > - instanceVariableNames: '' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-Models'! > > Item was removed: > - ----- Method: ModelTest>>testCopyDependents (in category 'tests') ----- > - testCopyDependents > - > - | bar foo | > - foo := Model new. > - foo addDependent: 42. > - self assert: {42} equals: foo dependents asArray. > - > - bar := foo copy. > - self assert: bar dependents isEmpty.! > > Item was removed: > - ----- Method: NumberTest>>testExactLog2 (in category 'tests') ----- > - testExactLog2 > - -10 to: 10 do: [:i | self assert: i equals: (2 raisedToInteger: i) log2]. > - Float emin - Float precision + 1 to: Float emax do: [:i | self assert: i equals: (1.0 timesTwoPower: i) log2].! > > Item was removed: > - ----- Method: NumberTest>>testLog2doesNotOverflow (in category 'tests') ----- > - testLog2doesNotOverflow > - "Note: though this is not a strict identity, we can use strict Float equality here" > - self assert: 3000.0 equals: ((1 bitShift: 3000) - 1) log2. > - self assert: 1500.0 equals: (((1 bitShift: 3000) - 1) / (1 bitShift: 1500)) log2.! > > Item was removed: > - ----- Method: NumberTest>>testLog2doesNotUnderflow (in category 'tests') ----- > - testLog2doesNotUnderflow > - "Note: though this is not a strict identity, we can use strict Float equality here" > - self assert: -2000.0 equals: ((1 bitShift: 2000) - 1) reciprocal log2! > > Item was removed: > - ----- Method: ObjectTest>>testCopyDependents (in category 'tests') ----- > - testCopyDependents > - > - | bar foo | > - foo := Object new. > - foo addDependent: 42. > - self assert: {42} equals: foo dependents asArray. > - > - bar := foo copy. > - self assert: bar dependents isEmpty.! > > Item was removed: > - ----- Method: ProcessTest>>genuineProcess (in category 'support') ----- > - genuineProcess > - > - "Usually, we don't want to expose this from the class under test." > - ^ Processor instVarNamed: 'genuineProcess'! > > Item was removed: > - ----- Method: ProcessTest>>testEvaluateOnBehalfOf (in category 'tests') ----- > - testEvaluateOnBehalfOf > - > - | p1 p2 sem results | > - self genuineProcess == Processor activeProcess > - ifFalse: [self fail: 'Cannot debug this test']. > - > - sem := Semaphore new. > - p1 := [] newProcess. > - p1 environmentAt: #foo put: 1. > - p2 := [ > - Processor activeProcess environmentAt: #foo put: 2. > - results := { > - Processor activeProcess environmentAt: #foo. > - self genuineProcess environmentAt: #foo. > - Processor activeProcess > - evaluate: [Processor activeProcess environmentAt: #foo] > - onBehalfOf: p1. > - Processor activeProcess > - evaluate: [self genuineProcess environmentAt: #foo] > - onBehalfOf: p1. > - Processor activeProcess environmentAt: #foo }. > - sem signal > - ] newProcess. > - > - p2 resume. > - sem wait. > - > - self assert: {2. 2. 1. 2. 2} equals: results.! > > Item was removed: > - ----- Method: ProcessTest>>testProcessFaithfulRunning (in category 'tests') ----- > - testProcessFaithfulRunning > - "While simulating a process using #runUntilErrorOrReturnFrom:, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." > - > - | process result | > - process := Process forBlock: [ > - result := Processor activeProcess environmentAt: #foo]. > - process environmentAt: #foo put: 42. > - > - process complete: process suspendedContext. > - > - self assert: 42 equals: result.! > > Item was removed: > - ----- Method: ProcessTest>>testProcessFaithfulSimulation (in category 'tests') ----- > - testProcessFaithfulSimulation > - "While simulating a process using the bytecode simulation machinery, process variables should be looked up in the process being simulated. Acceptance test for process-faithful debugging, see #evaluate:onBehalfOf:." > - > - | process result | > - process := Process forBlock: [ > - result := Processor activeProcess environmentAt: #foo]. > - process environmentAt: #foo put: 42. > - > - process runUntil: [:context | context isDead]. > - > - self assert: 42 equals: result.! > > Item was removed: > - ----- Method: PromiseTest>>testAnErrorInOnRejectedRejectsPromise (in category 'tests - monad') ----- > - testAnErrorInOnRejectedRejectsPromise > - "https://promisesaplus.com section 2.2.7.2" > - | p q error | > - p := Promise new. > - q := p ifRejected: [:e | (error := KeyNotFound new) signal]. > - p rejectWith: 1. > - self assert: p isRejected description: 'Original Promise not rejected'. > - self assert: q isRejected description: 'Broken Promise not rejected'. > - self assert: p error = 1. > - self assert: q error == error.! > > Item was changed: > ----- Method: PromiseTest>>testAnErrorInThenRejectsPromise (in category 'tests - monad') ----- > testAnErrorInThenRejectsPromise > + | p q | > - "https://promisesaplus.com section 2.2.7.2" > - | p q error | > p := Promise new. > + q := p then: [:v | KeyNotFound signal]. > - q := p then: [:v | (error := KeyNotFound new) signal]. > p resolveWith: 1. > self deny: p isRejected description: 'Original Promise rejected'. > + self assert: q isRejected description: 'Broken Promise not rejected'.! > - self assert: q isRejected description: 'Broken Promise not rejected'. > - self assert: p value = 1. > - self assert: q error == error.! > > Item was removed: > - ----- Method: PromiseTest>>testNilErrBlockPropagation (in category 'tests - monad') ----- > - testNilErrBlockPropagation > - "https://promisesaplus.com section 2.2.7.4" > - | p q | > - p := Promise new. > - q := p then: [:v | self error: 'Shouldn''t call resolvedBlock'] ifRejected: nil. > - p rejectWith: 1. > - self assert: p isRejected. > - self assert: q isRejected. > - self assert: p error equals: 1. > - self assert: q error equals: 1.! > > Item was removed: > - ----- Method: PromiseTest>>testNilResolvedBlockPropagation (in category 'tests - monad') ----- > - testNilResolvedBlockPropagation > - "https://promisesaplus.com section 2.2.7.3" > - | p q | > - p := Promise new. > - q := p then: nil ifRejected: [:e | self error: 'Shouldn''t call errBlock']. > - p resolveWith: 1. > - self assert: p isResolved. > - self assert: q isResolved. > - self assert: p value equals: 1. > - self assert: q value equals: 1.! > > Item was changed: > ----- Method: PromiseTest>>testifRejectedRunsBlockIfPromiseFails (in category 'tests - monad') ----- > testifRejectedRunsBlockIfPromiseFails > - "https://promisesaplus.com section 2.2.7.1" > | p q error | > error := nil. > p := Promise new. > + q := p ifRejected: [:e | error := e]. > - q := p ifRejected: [:e | error := e "N.B. returns a value, does not signal an Exception"]. > p rejectWith: KeyNotFound new. > + self assert: q isRejected. > + self assert: KeyNotFound equals: error class.! > - self assert: q isResolved. > - self assert: KeyNotFound equals: error class. > - self assert: q value == error.! > > Item was removed: > - Object subclass: #WriteBarrierAnotherStub > - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-WriteBarrier'! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var1 (in category 'accessing') ----- > - var1 > - ^ var1! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var10 (in category 'accessing') ----- > - var10 > - ^ var10! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var10: (in category 'accessing') ----- > - var10: anObject > - var10 := anObject! > > Item was removed: > - ----- Method: WriteBarrierAnotherStub>>var1: (in category 'accessing') ----- > - var1: anObject > - var1 := anObject! > > Item was removed: > - Object subclass: #WriteBarrierStub > - instanceVariableNames: 'var1 var2 var3 var4 var5 var6 var7 var8 var9 var10' > - classVariableNames: '' > - poolDictionaries: '' > - category: 'KernelTests-WriteBarrier'! > > Item was removed: > - ----- Method: WriteBarrierStub>>var1 (in category 'accessing') ----- > - var1 > - ^ var1! > > Item was removed: > - ----- Method: WriteBarrierStub>>var10 (in category 'accessing') ----- > - var10 > - ^ var10! > > Item was removed: > - ----- Method: WriteBarrierStub>>var10: (in category 'accessing') ----- > - var10: anObject > - var10 := anObject! > > Item was removed: > - ----- Method: WriteBarrierStub>>var1: (in category 'accessing') ----- > - var1: anObject > - var1 := anObject! > > Item was removed: > - TestCase subclass: #WriteBarrierTest > - instanceVariableNames: '' > - classVariableNames: 'ContextInstance' > - poolDictionaries: '' > - category: 'KernelTests-WriteBarrier'! > - > - !WriteBarrierTest commentStamp: '' prior: 0! > - My tests ensure the ReadOnly property of objects work properly. > - > - #testMutateIVObject is a good start to understand what is going on. > - > - The VM needs to be compiled with -DIMMUTABILTY= true for those tests to work.! > > Item was removed: > - ----- Method: WriteBarrierTest class>>initialize (in category 'initialization') ----- > - initialize > - > - ContextInstance := Context sender: nil receiver: self new method: self >> #alwaysWritableObjects arguments: #()! > > Item was removed: > - ----- Method: WriteBarrierTest>>alwaysReadOnlyObjects (in category 'guinea pigs') ----- > - alwaysReadOnlyObjects > - "Immediates are always immutable" > - ^ { 1 }! > > Item was removed: > - ----- Method: WriteBarrierTest>>alwaysWritableObjects (in category 'guinea pigs') ----- > - alwaysWritableObjects > - "Objects that currently can't be immutable" > - ^ { ContextInstance . > - Processor . > - Processor activeProcess }! > > Item was removed: > - ----- Method: WriteBarrierTest>>expectedFailures (in category 'expected failures') ----- > - expectedFailures > - Smalltalk supportsReadOnlyObjects ifFalse: > - [^self class testSelectors]. > - ^#( testMutateByteArrayUsingDoubleAtPut testMutateByteArrayUsingFloatAtPut ), > - ((Smalltalk classNamed: #MirrorPrimitives) > - ifNil: [#(testBasicProxyReadOnly testBasicProxyWritable testSetIsReadOnlySuccessProxy)] > - ifNotNil: [#()])! > > Item was removed: > - ----- Method: WriteBarrierTest>>maybeReadOnlyObjects (in category 'guinea pigs') ----- > - maybeReadOnlyObjects > - "ByteObject, Variable object, fixed sized object" > - ^ { { 1 . 2 . 3 } asByteArray . { 1 . 2 . 3 } . (MessageSend receiver: 1 selector: #+ argument: 2) }! > > Item was removed: > - ----- Method: WriteBarrierTest>>testAttemptToMutateLiterals (in category 'tests - object') ----- > - testAttemptToMutateLiterals > - | guineaPigs | > - guineaPigs := {#[1 2 3] . #(1 2 3) }. > - guineaPigs do: > - [ :guineaPig | > - self should: [guineaPig at: 1 put: 4] > - raise: ModificationForbidden]. > - > - self should: [guineaPigs first become: guineaPigs second ] > - raise: ModificationForbidden. > - > - self should: [ByteString adoptInstance: guineaPigs first] > - raise: ModificationForbidden. > - > - self should: [WeakArray adoptInstance: guineaPigs last] > - raise: ModificationForbidden! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicProxyReadOnly (in category 'tests - proxy') ----- > - testBasicProxyReadOnly > - self alwaysReadOnlyObjects do: [ :each | > - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: true ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicProxyWritable (in category 'tests - proxy') ----- > - testBasicProxyWritable > - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | > - self assert: (MirrorPrimitives isObjectReadOnly: each) equals: false ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicReadOnly (in category 'tests - object') ----- > - testBasicReadOnly > - self alwaysReadOnlyObjects do: [ :each | > - self assert: each isReadOnlyObject equals: true ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBasicWritable (in category 'tests - object') ----- > - testBasicWritable > - self alwaysWritableObjects , self maybeReadOnlyObjects do: [ :each | > - self assert: each isReadOnlyObject equals: false ]! > > Item was removed: > - ----- Method: WriteBarrierTest>>testBecomeReadOnly (in category 'tests - object') ----- > - testBecomeReadOnly > - | readOnlyArrays readOnlyByteArrays | > - readOnlyArrays := (1 to: 3) collect: [:n| (0 to: n) asArray beReadOnlyObject; yourself]. > - "N.B. if the targets are read-only this fails, which is correct for elementsForwardIdentityTo: since copyHash is implicitly true; > - we need to write a test for a putative elementsForwardIdentityNoCopyHashTo:" > - readOnlyByteArrays := (1 to: 3) collect: [:n| (0 to: n) asByteArray" beReadOnlyObject; yourself"]. > - self should: [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] > - raise: ModificationForbidden. > - [readOnlyArrays elementsForwardIdentityTo: readOnlyByteArrays] > - on: ModificationForbidden > - do: [:ex| > - false > - ifTrue: "This fails, but should succeed. I *think* it's to do with catching signals when resignalling" > - [(ex mirror detect: [:element| element isReadOnlyObject] ifNone: []) ifNotNil: > - [:readOnlyObj| readOnlyObj beWritableObject]] > - ifFalse: > - [ex mirror do: [:element| element beWritableObject]]. > - ex retryModification]. > - self assert: (readOnlyArrays allSatisfy: [:array| array class == ByteArray])! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingByteAtPut (in category 'tests - object') ----- > - testMutateByteArrayUsingByteAtPut > - | guineaPig | > - guineaPig := ByteArray new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig byteAt: 1 put: 12 ] > - raise: ModificationForbidden. > - > - [ guineaPig byteAt: 1 put: 12 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: 12. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - self > - should: [ guineaPig byteAt: 1 put: 13 ] > - raise: ModificationForbidden. > - > - [ guineaPig byteAt: 1 put: 13 ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig first equals: 13. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingDoubleAtPut (in category 'tests - object') ----- > - testMutateByteArrayUsingDoubleAtPut > - | guineaPig | > - guineaPig := ByteArray new: 8. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] > - raise: ModificationForbidden. > - > - [ guineaPig doubleAt: 1 put: (2 raisedTo: 65) asFloat ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: (2 raisedTo: 65) asFloat. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - self > - should: [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] > - raise: ModificationForbidden. > - > - [ guineaPig doubleAt: 1 put: (2 raisedTo: 64) asFloat ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig first equals: (2 raisedTo: 64) asFloat. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteArrayUsingFloatAtPut (in category 'tests - object') ----- > - testMutateByteArrayUsingFloatAtPut > - | guineaPig | > - guineaPig := ByteArray new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig floatAt: 1 put: 1.0 ] > - raise: ModificationForbidden. > - > - [ guineaPig floatAt: 1 put: 1.0 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: 1.0. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig floatAt: 1 put: 2.0 ] > - raise: ModificationForbidden. > - > - [ guineaPig floatAt: 1 put: 2.0 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig first equals: 2.0. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingAtPut (in category 'tests - object') ----- > - testMutateByteStringyUsingAtPut > - | guineaPig | > - guineaPig := ByteString new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: $h ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: $h ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: $h. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: $g ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: $g ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume ]. > - > - self assert: guineaPig first equals: $g. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteStringyUsingByteAtPut (in category 'tests - object') ----- > - testMutateByteStringyUsingByteAtPut > - | guineaPig | > - guineaPig := ByteString new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig byteAt: 1 put: 100 ] > - raise: ModificationForbidden. > - > - [ guineaPig byteAt: 1 put: 100 ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first asciiValue equals: 100! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateByteSymbolUsingPrivateAtPut (in category 'tests - object') ----- > - testMutateByteSymbolUsingPrivateAtPut > - | guineaPig | > - [guineaPig := #hello. > - guineaPig beReadOnlyObject. > - > - self > - should: ((guineaPig class includesSelector: #pvtAt:put:) > - ifTrue: [[ guineaPig perform: #pvtAt:put: with: 1 with: $q ]] "Squeak refuses to compile non-self sends of pvt* selectors." > - ifFalse: [[ guineaPig privateAt: 1 put: $q ]]) > - raise: ModificationForbidden ] > - ensure: > - [ guineaPig beWritableObject ]. > - > - self assert: guineaPig first equals: $h! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateIVObject (in category 'tests - object') ----- > - testMutateIVObject > - | guineaPig | > - guineaPig := MessageSend new. > - guineaPig beReadOnlyObject. > - [ guineaPig receiver: 1 ] > - on: ModificationForbidden > - do: [ :modification | "Surely a NoModification error" ]. > - guineaPig > - beWritableObject; > - selector: #+; > - beReadOnlyObject. > - [ guineaPig arguments: #(2) ] > - on: ModificationForbidden > - do: [ :modification |"Surely a NoModification error" ]. > - self assert: guineaPig receiver isNil. > - self assert: guineaPig arguments isNil. > - self assert: guineaPig selector == #+.! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectClass (in category 'tests - object') ----- > - testMutateObjectClass > - | guineaPig | > - guineaPig := WriteBarrierStub new. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] > - raise: ModificationForbidden. > - > - [ guineaPig primitiveChangeClassTo: WriteBarrierAnotherStub new ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig class equals: WriteBarrierAnotherStub! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectClassViaAdoption (in category 'tests - object') ----- > - testMutateObjectClassViaAdoption > - | guineaPig | > - guineaPig := WriteBarrierStub new. > - guineaPig beReadOnlyObject. > - > - self > - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - raise: ModificationForbidden. > - > - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig class equals: WriteBarrierAnotherStub. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - self > - should: [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - raise: ModificationForbidden. > - > - [ WriteBarrierAnotherStub adoptInstance: guineaPig ] > - on: ModificationForbidden > - do: [ :modification | > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume]. > - > - self assert: guineaPig class equals: WriteBarrierAnotherStub. > - self assert: guineaPig isReadOnlyObject! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectFirstInstVarWithManyVars (in category 'tests - object') ----- > - testMutateObjectFirstInstVarWithManyVars > - | guineaPig failure | > - guineaPig := WriteBarrierStub new. > - guineaPig beReadOnlyObject. > - failure := [ guineaPig var1: #test ] on: ModificationForbidden do: [:err | err]. > - > - self assert: failure fieldIndex equals: 1! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectInstVarShouldCatchRightFailure (in category 'tests - object') ----- > - testMutateObjectInstVarShouldCatchRightFailure > - | guineaPig failure | > - guineaPig := MessageSend new. > - guineaPig beReadOnlyObject. > - failure := [ guineaPig receiver: #test ] on: ModificationForbidden do: [:err | err]. > - > - self assert: failure object == guineaPig. > - self assert: failure newValue equals: #test. > - self assert: failure fieldIndex equals: 1.! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingAtPut (in category 'tests - object') ----- > - testMutateObjectInstVarUsingAtPut > - | guineaPig | > - guineaPig := Array new: 5. > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: #test ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: #test ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModification ]. > - > - self assert: guineaPig first equals: #test. > - self deny: guineaPig isReadOnlyObject. > - > - guineaPig beReadOnlyObject. > - > - self > - should: [ guineaPig at: 1 put: #test ] > - raise: ModificationForbidden. > - > - [ guineaPig at: 1 put: #test ] > - on: ModificationForbidden > - do: [:modification | > - self assert: modification fieldIndex equals: 1. > - modification object beWritableObject. > - modification retryModificationNoResume. > - modification object beReadOnlyObject. > - modification resume ]. > - > - self assert: guineaPig first equals: #test. > - self assert: guineaPig isReadOnlyObject > - ! > > Item was removed: > - ----- Method: WriteBarrierTest>>testMutateObjectInstVarUsingBasicAtPut (in category 'tests - object') --- -------------- next part -------------- An HTML attachment was scrubbed... URL: From m at jaromir.net Sun Mar 21 20:12:02 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 21 Mar 2021 15:12:02 -0500 (CDT) Subject: [squeak-dev] Refactoring #terminate to get rid of 'cannot return' errors etc. In-Reply-To: <1615912179202-0.post@n4.nabble.com> References: <1615708691721-0.post@n4.nabble.com> <1615912179202-0.post@n4.nabble.com> Message-ID: <1616357522646-0.post@n4.nabble.com> Hi Christoph, all: > your > proposal would not directly allow us to remove the current #isTerminated > logic but only extend it, right? Because there could still be processes > not > using the new #terminated marker and thus requiring us to keep the old > mechanisms. On second thought I think the proposal would allow us to simplify the current #isTerminated logic. It's actually a matter of a policy: do we want users to create processes other than the "newProcess" way? If not than we can remove the condition checking the last instruction of the bottom context, because newProcess no longer needs it, leaving just one condition: is the process inside the #terminated method? (after eliminating defunct processes). Like this: Process >> isTerminated "Answer if the receiver is terminated, i.e. if the receiver is not active and one of the following conditions is met: (1) the receiver is a defunct process (suspendedContext = nil or pc = nil) (2) the receiver is suspended within a method with isTerminated pragma" self isActiveProcess ifTrue: [^false]. ^suspendedContext isNil or: [ suspendedContext isDead or: [ (suspendedContext method pragmaAt: #isTerminated) notNil]] I used a new pragma instead of hardcoding the class and the selector of the terminal method: Process >> terminated "When I reach this method, I'm terminated. Suspending or terminating me is harmless." thisContext terminateTo: nil. "sets thisContext sender to nil" self suspend. ^thisContext restart You can check it out in this changeset: Refactor_#terminate_2_without_atEnd.cs What do you think? best, ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From giovanni at corriga.net Mon Mar 22 18:41:25 2021 From: giovanni at corriga.net (Giovanni Corriga) Date: Mon, 22 Mar 2021 18:41:25 +0000 Subject: [squeak-dev] UK Smalltalk User Group meeting - Wednesday March 31st Message-ID: The next meeting of the UK Smalltalk User Group will be on Wednesday, March 31st. In this meeting, Juan Vuletich will present a Vector Graphic implementation in Cuis Smalltalk. Graphics for interactive software have traditionally been constrained for performance reasons. The consequence is that most software has serious trouble adapting to higher resolution screens, requires platform specific widget kits, provides limited functionality, and has sub optimal visual quality. But improvements in computing power over the last couple of decades enable a brighter future: Cuis Smalltalk provides a VectorGraphics based implementation of the Morphic UI framework that addresses all these issues. Juan is a long standing member of the Open Source Smalltalk community. He started Cuis Smalltalk ( https://www.cuis-smalltalk.org/ ) 12 years ago and has led it ever since. He has been contributing kernel code to Squeak and the Squeak VM for over 20 years. He holds an Ms.Sc. in Computer Science from the University of Buenos Aires. Given the current COVID-19 restrictions, this will be an online meeting from home. If you'd like to join us, please sign up in advance on the meeting's Meetup page ( https://www.meetup.com/UKSTUG/events/cbklbryccfbgc/ ) to receive the meeting details. Don’t forget to bring your laptop and drinks! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Mon Mar 22 18:59:20 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Mon, 22 Mar 2021 18:59:20 +0000 Subject: [squeak-dev] Please merge | The Inbox: Kernel-ct.1382.mcz In-Reply-To: References: , , Message-ID: <64d5ef4470ab4b11b136674049ec64ca@student.hpi.uni-potsdam.de> Hi all, would it be possible to merge this contribution soon, provided that you agree with the proposal? :-) I'm already making some larger efforts for dealing with not-yet-approved Trunk fixes for my current side projects (concretely SimulationStudio, but TelegramBot and TelegramSmalltalkBot are affected as well), but since I have uploaded two different fixes for Context >> #doPrimitive:method:receiver:args: to the inbox, merging both of them in smalltalkCI before running my tests is simply not possible any longer because they conflict with each other (only from the perspective of Monticello: from a semantical perspective, they work together very well). I really would like not to need to write a better conflict resolution merger for Monticello, just in order to get my current PR for SimulationStudio merged ... Thanks in advance! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Thiede, Christoph Gesendet: Dienstag, 16. März 2021 12:22 Uhr An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Kernel-ct.1382.mcz > Also see Magnitude >> #between:and: :-) Yeah, I was aware of this, but #between:and: is not inlined ... Probably this was a case of premature optimization. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Dienstag, 16. März 2021 09:55:15 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Kernel-ct.1382.mcz +1 Also see Magnitude >> #between:and: :-) Best, Marcel Am 15.03.2021 13:52:19 schrieb commits at source.squeak.org : A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1382.mcz ==================== Summary ==================== Name: Kernel-ct.1382 Author: ct Time: 15 March 2021, 1:52:03.249869 pm UUID: e108423f-661f-4d4f-9ad8-c667c3995b32 Ancestors: Kernel-mt.1381 Proposal: Revises usage and handling of primitive 19, also known as the simulation guard. Don't use it in #newProcess and variants since they don't involve any actual control logic. Instead, also show a simulation warning when debugging a control primitive (primitiveSignal primitiveWait primitiveResume primitiveSuspend). Improves integration of simulation guard warnings by signaling a Warning on the simulator stack rather than spawning a debugger on the debugged process. This also makes it easier to handle these warnings in a non-interactive context. See http://forum.world.st/Simulation-guard-lt-primitive-19-gt-crashes-the-image-td5127443.html and http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html for more information. Reuploaded to resolve merge conflict with Kernel-mt.1381. Replaces Kernel-ct.1381, which can be moved into the treated inbox. =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + ["Transcript + cr; + nextPutAll: 'Processor activeProcess '; + nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); + nextPutAll: ' owner'; + flush." + value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Mon Mar 22 21:45:59 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Mon, 22 Mar 2021 21:45:59 +0000 Subject: [squeak-dev] The Trunk: Kernel-eem.1367.mcz In-Reply-To: <62C9EC8C-9208-4531-8B1B-197A195E4DB0@gmail.com> References: , <62C9EC8C-9208-4531-8B1B-197A195E4DB0@gmail.com> Message-ID: <19ebf8e16d1b433aa6c325759e7e864c@student.hpi.uni-potsdam.de> Hi Eliot, I have just found another bug that is caused by this change: You cannot debug MirrorPrimitiveTest >> #testMirrorClass any longer - more in general, you cannot debug "ProtoObject new" any longer, because the return value of primitiveNew does not understand #isArray. I think this is very clearly a bug? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Eliot Miranda Gesendet: Dienstag, 2. März 2021 18:05:37 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] The Trunk: Kernel-eem.1367.mcz On Mar 2, 2021, at 8:21 AM, Thiede, Christoph wrote:  Hi Eliot, then I think there is an issue with the argument name. In #callPrimitive:, for example, it is named more specifically, maybePrimFailToken. In #doPrimitive:method:receiver:args:, we may feed it with the result of #tryPrimitive:withArgs: which can be anything, not only a context or fail token. Here is a second example: Object subclass: #ContextHack instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'CT-Experiments'. ContextHack class compile: 'isArray self error: #hacked'. ContextHack new class "through" I still think that this is fuss over nothing. Even if the system did keep running with a Context that answered true to isArray it would have to have a stack pointer of 2 and a first arg/temp that was the PrimFailToken. You yourself complained of the performance of testing for the PrimFailToken. isArray is faster than objectClass == Array. We haven’t seen any issues with this. I suggest that if it ain’t broke we don’t fix it. Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Eliot Miranda Gesendet: Dienstag, 2. März 2021 16:27 Uhr An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] The Trunk: Kernel-eem.1367.mcz Hi Christoph, On Mar 2, 2021, at 5:17 AM, Thiede, Christoph wrote:  Hi Eliot, thanks for the fix! Sorry for raising the same question again, but wouldn't it still be safer to dispense with the #isArray call here? It allows the simulated code to break out of the simulation by overriding #isArray anywhere. As I understand it no. The clue is in the variable name. contextOrPrimFailToken can only ever be a Context or an Array, so the send of isArray serves only to quickly differentiate between a Context and an Array. The message doesn’t get sent to any other kinds of object at that point so the concern that other classes may define isArray does not apply here. I think I posted a proof of concept here: http://forum.world.st/The-Trunk-Kernel-eem-1366-mcz-tp5126558p5126713.html :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Dienstag, 2. Februar 2021 03:57:12 An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-eem.1367.mcz Eliot Miranda uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-eem.1367.mcz ==================== Summary ==================== Name: Kernel-eem.1367 Author: eem Time: 1 February 2021, 6:57:09.713484 pm UUID: def9aaa1-eb71-4da5-8f86-85856d9b88ad Ancestors: Kernel-eem.1366 Fix mistake in the previous commit. Thanks Levente! =============== Diff against Kernel-eem.1366 =============== Item was changed: ----- Method: Context>>isPrimFailToken: (in category 'private') ----- + isPrimFailToken: contextOrPrimFailToken + "Answer if contextOrPrimFailToken, which will either be a Context object or + a primitive fail token (a tuple of the PrimitiveFailToken unique object and + a primitive failure code), is the latter. This should only be used with the + (possibly indirect) results of Context>>doPrimitive:method:receiver:args:" + ^contextOrPrimFailToken isArray + and: [contextOrPrimFailToken size = 2 + and: [(contextOrPrimFailToken at: 1) == PrimitiveFailToken]]! - isPrimFailToken: anObject - ^(self objectClass: anObject) isArray - and: [anObject size = 2 - and: [(anObject at: 1) == PrimitiveFailToken]]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From christoph.thiede at student.hpi.uni-potsdam.de Tue Mar 23 12:16:18 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Tue, 23 Mar 2021 07:16:18 -0500 (CDT) Subject: [squeak-dev] Refactoring #terminate to get rid of 'cannot return' errors etc. In-Reply-To: <1616357522646-0.post@n4.nabble.com> References: <1615708691721-0.post@n4.nabble.com> <1615912179202-0.post@n4.nabble.com> <1616357522646-0.post@n4.nabble.com> Message-ID: <1616501778450-0.post@n4.nabble.com> Hi Jaromir, > Real life examples? I'm thinking parallel computing where one process can > terminate while another one running in parallel might still want to resume > it assuming or hoping it is only suspended (without an explicit check that > would raise an exception). Just a thought... Hm, in this example, you could also use a critical section to check whether the process is terminated and then handle it respectively, couldn't you? I still think we need a better example to conduct this discussion. Still, I don't have great parallel programming experiences, so this is just a naive assumption. Probably someone else can give their statement? :-) > 2. Readability of the code (newProcess's logic isn't easy to decode) Yes, this is probably your most important reason so far. :-) > 3. Easy way to spot a terminated process while debugging :) > (suspendedContext = Process>>#terminated) You could also improve the #printString implementation of Process to reach this goal. :-) > However, replacing: > ctxt setSender: nil receiver: self method: > (Process>>#terminated) arguments: {}. > > with: > ctxt := Context sender: nil receiver: self method: > (Process>>#terminated) arguments: {} > doesn't update the stack frame because nothing happens After taking a second look at this part of your changeset ... Why do you need to manipulate the stack *after* terminating the process? Wouldn't it be possible to set the sender of the prior bottom context to the #terminated method (provided that it does not already point to that) so that #popTo: will automatically activate this context unless the termination was aborted? Pseudo: (ctxt bottomContext method pragmaAt: #isTerminated) ifNil: [ctxt bottomContext privSender: (Context sender: nil receiver: self method: Process >> #terminated)]. arguments: {} ctxt := self popTo: suspendedContext bottomContext. (ctxt bottomContext method pragmaAt: #isTerminated) ifNil: [self debug: ctxt title: 'Unwind error during termination']. > It's actually a matter of a policy: do we want users to create processes > other than the "newProcess" way? That is an interesting question. When designing a new system, I would definitively agree, just because it makes it easier to distinguish between corrupted processes and valid terminated processes. Another aspect is compatibility, and at the very least Process class >> #forContext:priority: is a public instance creation method which we would need to deprecate for public usage (with the exception of #newProcess...). The next Squeak release will have a new major version number, but still, I think we should not destroy bridges behind us and limit compatibility more than necessary. That being said ... I don't know, again. Third opinions desired! > I used a new pragma instead of hardcoding the class and the selector of > the terminal method I just saw that, but what's the reason for it? Pragmas to mark methods are usually meant as extension points. So I could define any other method with this pragma anywhere in my image and suspending a process in this method would magically make it be displayed as terminated. Do we really need this? Do you have any concrete example where Process >> #terminated does not suffice? :-) I have just another question, being completely agnostic of the relevant VM implementation. How does the VM know when a process can be gargabe-collected? I don't think it will invoke the image-side #isTerminated check, so it will probably define its own logic for checking termination. If this is the case, we should be very careful to keep both implementation in sync to avoid dangling process instances in the image. Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From christoph.thiede at student.hpi.uni-potsdam.de Wed Mar 24 11:49:53 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Wed, 24 Mar 2021 06:49:53 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1616011686241-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> <1615901797162-0.post@n4.nabble.com> <1616011686241-0.post@n4.nabble.com> Message-ID: <1616586593553-0.post@n4.nabble.com> Hi Jaromir, > The main difference between your non-local example: > > [self error: 'e1'] ensure: [^2] > > and my one without the non-local return: > > [self error: 'e1'] ensure: [self error: 'e2'] > > is that in your case the ^2 interrupts the orderly unwinding/termination > and the UI process continues as if still in simulation (because of the > missed effective process reset) - until another exception happens > *somewhen* in the future - while in my examples the next exception > resetting the effectiveProcess happens right away in the ensure block, > presenting "only" the Unwind error on the outside. Very precisely. For this reason, I suggest leaving aside my non-local return example for the moment and focusing on your much simpler case instead. :-) I have been sleeping over these problems a few times ... It seems strange to me that the termination logic needs to involve a send to #runUntilErrorOrReturnFrom: at all (also via #popTo:). This is usually meant to be used by the debugger only (that's also why it has this special return value format). In the current Trunk, the behavior of #runUntilErrorOrReturnFrom: to catch UnhandledErrors is not even used at all in #terminate (though I added rudimentary support to it in my previous changeset). I have the feeling that we should not catch UnhandledErrors in this place at all since there is not any present debugger that would process these errors. Ideally, I would like to just hand over control to the process to be terminated and have it unwind the entire stack down to the bottom context. Again from a rather conceptual point of view: How useful is it to terminate a process "remotely", i.e. simulating it from the outside? Intuitively, I would rather have said that terminating a process is a request to the process to "please stop everything you are just doing and only unwind your current operations". Why can't we just activate the relevant return context on the process (see #popTo:) and then resume it again? Then everything exceptional that might happen during the unwinding would behave exactly like if the process weren't being unwound right now. The difference, though, would be that the #terminate would return before the process would be unwound, and we would need to rethink the priority of the process to be terminated. For example, we could give it the priority of the active process + 1 or, in the worst case, use busy waiting in #terminate until the process is terminated. Probably these considerations have been the reason to implement #terminate in the current way. But conceptionally, wouldn't such an approach be closer to the conceptual meaning of terminating a process? Just thinking aloud ... I'm looking forward to your opinion! :-) > This scenario, however uncovers a weakness in the #isTerminated, reporting > the currently executing process with effectiveProcess assigned, as > terminated and as a result preventing Process Browser to reveal such a > pathological situation (which is precisely when you need to see it). I don't think so ... The violated invariant in this situation is that the effectiveProcess variable has not been reset. In general, Process >> #isTerminated should indeed consider the effectiveProcess. Debugging "Processor activeProcess isTerminated" should always work exactly like executing it outside the debugger. :-) Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Wed Mar 24 15:36:29 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 24 Mar 2021 15:36:29 0000 Subject: [squeak-dev] The Trunk: Tools-tonyg.1032.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-tonyg.1032.mcz ==================== Summary ==================== Name: Tools-tonyg.1032 Author: tonyg Time: 24 March 2021, 4:36:27.132139 pm UUID: 1077d608-e946-49dd-99f0-3a55ffe06e81 Ancestors: Tools-mt.1031 Repair Browser to allow selection of classes in non-default Environments. =============== Diff against Tools-mt.1031 =============== Item was changed: ----- Method: Browser>>addTrait (in category 'traits') ----- addTrait | input trait | input := UIManager default request: 'add trait'. input isEmptyOrNil ifFalse: [ + trait := self environment classNamed: input. - trait := Smalltalk classNamed: input. (trait isNil or: [trait isTrait not]) ifTrue: [ ^self inform: 'Input invalid. ' , input , ' does not exist or is not a trait']. self selectedClass setTraitComposition: self selectedClass traitComposition asTraitComposition + trait. self contentsChanged]. ! Item was changed: ----- Method: Browser>>hasClassSelected (in category 'class list') ----- hasClassSelected + ^ selectedClassName notNil and: [(self environment classNamed: selectedClassName) notNil]! - ^ selectedClassName notNil and: [(Smalltalk classNamed: selectedClassName) notNil]! From tonyg at leastfixedpoint.com Wed Mar 24 15:40:17 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Wed, 24 Mar 2021 16:40:17 +0100 Subject: [squeak-dev] ToolSet and Environments (was Re: The Trunk: Tools-tonyg.1032.mcz) In-Reply-To: References: Message-ID: <1c482d79-a8c1-07cf-dd73-15cd93eb89dc@leastfixedpoint.com> Hi all, I've been experimenting with Environments a little. They look promising, but if I understand correctly we don't have much in the way of tool support for them yet? Would a patch to ToolSet be welcome to add, say, `browseEnvironment:` and a convenience `Environment >> browse` to the various ToolSets? It took a little digging before I found (Browser new selectEnvironment: someEnvironment) buildAndOpenFullBrowser Further than that, there seems not to be many users of Environment's class-side Instances variable yet. Is it intended to be a kind of registry of available in-image Environments? Would some thinking about how to surface those in the tooling be welcome? Tony On 3/24/21 3:36 PM, commits at source.squeak.org wrote: > Tony Garnock-Jones uploaded a new version of Tools to project The Trunk: > http://source.squeak.org/trunk/Tools-tonyg.1032.mcz > > ==================== Summary ==================== > > Name: Tools-tonyg.1032 > Author: tonyg > Time: 24 March 2021, 4:36:27.132139 pm > UUID: 1077d608-e946-49dd-99f0-3a55ffe06e81 > Ancestors: Tools-mt.1031 > > Repair Browser to allow selection of classes in non-default Environments. > > =============== Diff against Tools-mt.1031 =============== > > Item was changed: > ----- Method: Browser>>addTrait (in category 'traits') ----- > addTrait > | input trait | > input := UIManager default request: 'add trait'. > input isEmptyOrNil ifFalse: [ > + trait := self environment classNamed: input. > - trait := Smalltalk classNamed: input. > (trait isNil or: [trait isTrait not]) ifTrue: [ > ^self inform: 'Input invalid. ' , input , ' does not exist or is not a trait']. > self selectedClass setTraitComposition: self selectedClass traitComposition asTraitComposition + trait. > self contentsChanged]. > ! > > Item was changed: > ----- Method: Browser>>hasClassSelected (in category 'class list') ----- > hasClassSelected > + ^ selectedClassName notNil and: [(self environment classNamed: selectedClassName) notNil]! > - ^ selectedClassName notNil and: [(Smalltalk classNamed: selectedClassName) notNil]! > > From tonyg at leastfixedpoint.com Wed Mar 24 15:42:24 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Wed, 24 Mar 2021 16:42:24 +0100 Subject: [squeak-dev] [ann] Radial Menu for Squeak In-Reply-To: <3b78bbc79730498c815fe33294f1160d@student.hpi.uni-potsdam.de> References: <3b78bbc79730498c815fe33294f1160d@student.hpi.uni-potsdam.de> Message-ID: <609de4d9-2a63-ade2-3c4e-14aa5eee5e04@leastfixedpoint.com> On 3/19/21 3:53 PM, Thiede, Christoph wrote: > today I have only something small for you, not even worth the capital > letters in "[ann]". :-) YES this looks wonderful! It could be very good with a touch (and, in particular, multitouch?) input. I look forward to trying it out on my Squeak-on-a-cellphone experiment! Thank you! Regards, Tony From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 24 16:15:25 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 24 Mar 2021 16:15:25 +0000 Subject: [squeak-dev] [ann] Radial Menu for Squeak In-Reply-To: <609de4d9-2a63-ade2-3c4e-14aa5eee5e04@leastfixedpoint.com> References: <3b78bbc79730498c815fe33294f1160d@student.hpi.uni-potsdam.de>, <609de4d9-2a63-ade2-3c4e-14aa5eee5e04@leastfixedpoint.com> Message-ID: Oh, this sounds interesting! Please keep me up to date here! :-) Best, Christoph ________________________________ Von: Tony Garnock-Jones Gesendet: Mittwoch, 24. März 2021 16:42:24 An: The general-purpose Squeak developers list; Thiede, Christoph Betreff: Re: [squeak-dev] [ann] Radial Menu for Squeak On 3/19/21 3:53 PM, Thiede, Christoph wrote: > today I have only something small for you, not even worth the capital > letters in "[ann]". :-) YES this looks wonderful! It could be very good with a touch (and, in particular, multitouch?) input. I look forward to trying it out on my Squeak-on-a-cellphone experiment! Thank you! Regards, Tony -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 24 16:22:24 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 24 Mar 2021 16:22:24 +0000 Subject: [squeak-dev] ToolSet and Environments (was Re: The Trunk: Tools-tonyg.1032.mcz) In-Reply-To: <1c482d79-a8c1-07cf-dd73-15cd93eb89dc@leastfixedpoint.com> References: , <1c482d79-a8c1-07cf-dd73-15cd93eb89dc@leastfixedpoint.com> Message-ID: <234ff1ae796148ea9a0e0ace79c62cc7@student.hpi.uni-potsdam.de> Hi Tony, > Would a patch to ToolSet be welcome to add, say, `browseEnvironment:` and a convenience `Environment >> browse` to the various ToolSets? To me, this looks like a useful enhancement! > Would some thinking about how to surface those in the tooling be welcome? Definitively! Maybe we could add an item to the browser's window menu that pops up an environment selector (basically UIManager chooseFrom... and an accessor for Environment Instances) to change the currently visible environment in a browser? How would this look like in a PackagePaneBrowser? An important use case for Environments that I could think of would be to clone a class (hierarchy) to edit a copy of it and replacing the original class in the main environment. For example, when refactoring the Compiler ... I think we would need much more tooling for this and probably also some tests. I don't know how well environments are being supported right now - but for example, they are not even nestable at the moment, which would be helpful for the use case I have given. This is an interesting construction site! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Tony Garnock-Jones Gesendet: Mittwoch, 24. März 2021 16:40:17 An: The general-purpose Squeak developers list Betreff: [squeak-dev] ToolSet and Environments (was Re: The Trunk: Tools-tonyg.1032.mcz) Hi all, I've been experimenting with Environments a little. They look promising, but if I understand correctly we don't have much in the way of tool support for them yet? Would a patch to ToolSet be welcome to add, say, `browseEnvironment:` and a convenience `Environment >> browse` to the various ToolSets? It took a little digging before I found (Browser new selectEnvironment: someEnvironment) buildAndOpenFullBrowser Further than that, there seems not to be many users of Environment's class-side Instances variable yet. Is it intended to be a kind of registry of available in-image Environments? Would some thinking about how to surface those in the tooling be welcome? Tony On 3/24/21 3:36 PM, commits at source.squeak.org wrote: > Tony Garnock-Jones uploaded a new version of Tools to project The Trunk: > http://source.squeak.org/trunk/Tools-tonyg.1032.mcz > > ==================== Summary ==================== > > Name: Tools-tonyg.1032 > Author: tonyg > Time: 24 March 2021, 4:36:27.132139 pm > UUID: 1077d608-e946-49dd-99f0-3a55ffe06e81 > Ancestors: Tools-mt.1031 > > Repair Browser to allow selection of classes in non-default Environments. > > =============== Diff against Tools-mt.1031 =============== > > Item was changed: > ----- Method: Browser>>addTrait (in category 'traits') ----- > addTrait > | input trait | > input := UIManager default request: 'add trait'. > input isEmptyOrNil ifFalse: [ > + trait := self environment classNamed: input. > - trait := Smalltalk classNamed: input. > (trait isNil or: [trait isTrait not]) ifTrue: [ > ^self inform: 'Input invalid. ' , input , ' does not exist or is not a trait']. > self selectedClass setTraitComposition: self selectedClass traitComposition asTraitComposition + trait. > self contentsChanged]. > ! > > Item was changed: > ----- Method: Browser>>hasClassSelected (in category 'class list') ----- > hasClassSelected > + ^ selectedClassName notNil and: [(self environment classNamed: selectedClassName) notNil]! > - ^ selectedClassName notNil and: [(Smalltalk classNamed: selectedClassName) notNil]! > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 24 18:00:16 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 24 Mar 2021 18:00:16 +0000 Subject: [squeak-dev] X Server implementation for Squeak Message-ID: Hi all, just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: From Das.Linux at gmx.de Wed Mar 24 18:09:43 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Wed, 24 Mar 2021 19:09:43 +0100 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: References: Message-ID: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de> Hi Christoph > On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: > > Hi all, > > just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) There's RFB (aka VNC)… It works surprisingly well… BEst -tobias From tim at rowledge.org Wed Mar 24 18:27:18 2021 From: tim at rowledge.org (tim Rowledge) Date: Wed, 24 Mar 2021 11:27:18 -0700 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de> References: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de> Message-ID: > On 2021-03-24, at 11:09 AM, Tobias Pape wrote: > > Hi Christoph > >> On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: >> >> Hi all, >> >> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) > > There's RFB (aka VNC)… > It works surprisingly well… It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the http://source.squeak.org/ss repository - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Strange OpCodes: SVE: Skip on Vernal Equinox From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 24 18:48:52 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 24 Mar 2021 18:48:52 +0000 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: References: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de>, Message-ID: <423a0f83ee0441be99a63cc20230373d@student.hpi.uni-potsdam.de> Hi, sounds interesting. Does it still work for anyone in Trunk? I tried RFBServer start: 1 and then in a terminal $ DISPLAY=:1.0 xmessage foo but it said Error: Can't open display: :1.0 However, I got a Windows firewall warning so the image does indeed open a connection (and also starts a background process in the image). Did I miss anything? Apart from that, here are some more conceptual questions: How different are VNC and X11 actually? Afaik VNC is only used to stream entire screens while X11 is more fine-granular and allows to stream single windows. For what I proposed to do (use Morphic as a window manager), VNC would not suffice, would it? And how important is that difference from the implementational PoV? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von tim Rowledge Gesendet: Mittwoch, 24. März 2021 19:27:18 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] X Server implementation for Squeak > On 2021-03-24, at 11:09 AM, Tobias Pape wrote: > > Hi Christoph > >> On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: >> >> Hi all, >> >> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) > > There's RFB (aka VNC)… > It works surprisingly well… It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the http://source.squeak.org/ss repository - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Strange OpCodes: SVE: Skip on Vernal Equinox -------------- next part -------------- An HTML attachment was scrubbed... URL: From gettimothy at zoho.com Wed Mar 24 18:49:14 2021 From: gettimothy at zoho.com (gettimothy) Date: Wed, 24 Mar 2021 14:49:14 -0400 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: References: Message-ID: <1786591c059.c936d5e786075.7600393408649137933@zoho.com> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) Best, Christoph Hi Christoph, I would love to have Morphic windows display in my X Window Manager as regular X windows--like XTerm, XEyes..etc. That is independently of the Morphic world. Do you think this is doable? cordially, -------------- next part -------------- An HTML attachment was scrubbed... URL: From gettimothy at zoho.com Wed Mar 24 18:50:25 2021 From: gettimothy at zoho.com (gettimothy) Date: Wed, 24 Mar 2021 14:50:25 -0400 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: <423a0f83ee0441be99a63cc20230373d@student.hpi.uni-potsdam.de> References: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de>, <423a0f83ee0441be99a63cc20230373d@student.hpi.uni-potsdam.de> Message-ID: <1786592d8ed.108d6744886097.5803564698084538526@zoho.com> Do you need to do an 'xhost+"  from the CLI to allow "foreign" windows to display? just grasping here... ---- On Wed, 24 Mar 2021 14:48:52 -0400 Thiede, Christoph wrote ---- Hi, sounds interesting. Does it still work for anyone in Trunk? I tried RFBServer start: 1 and then in a terminal $ DISPLAY=:1.0 xmessage foo but it said Error: Can't open display: :1.0 http://www.hpi.de/ However, I got a Windows firewall warning so the image does indeed open a connection (and also starts a background process in the image). Did I miss anything? Apart from that, here are some more conceptual questions: How different are VNC and X11 actually? Afaik VNC is only used to stream entire screens while X11 is more fine-granular and allows to stream single windows. For what I proposed to do (use Morphic as a window manager), VNC would not suffice, would it? And how important is that difference from the implementational PoV? :-) Best, Christoph Von: Squeak-dev im Auftrag von tim Rowledge Gesendet: Mittwoch, 24. März 2021 19:27:18 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] X Server implementation for Squeak   > On 2021-03-24, at 11:09 AM, Tobias Pape wrote: > > Hi Christoph > >> On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: >> >> Hi all, >> >> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) > > There's RFB (aka VNC)… > It works surprisingly well… It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the http://source.squeak.org/ss repository  - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. tim -- tim Rowledge; mailto:tim at rowledge.org; http://www.rowledge.org/tim Strange OpCodes: SVE: Skip on Vernal Equinox -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Wed Mar 24 18:56:39 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Wed, 24 Mar 2021 18:56:39 +0000 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: <1786592d8ed.108d6744886097.5803564698084538526@zoho.com> References: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de>, <423a0f83ee0441be99a63cc20230373d@student.hpi.uni-potsdam.de>, <1786592d8ed.108d6744886097.5803564698084538526@zoho.com> Message-ID: <52c843660a3e48e5af09244d5cdf65ee@student.hpi.uni-potsdam.de> Hi Timothy, > Do you need to do an 'xhost+" from the CLI to allow "foreign" windows to display? Unfortunately, it did not help. I'm probably making things even more complicated by using WSL (Windows Subsystem for Linux) for my experiments ... However, together with VcXsrv, I am generally able to view WSL application in my Windows 10 desktop manager. > I would love to have Morphic windows display in my X Window Manager as regular X windows--like XTerm, XEyes..etc. That is independently of the Morphic world. > > Do you think this is doable? You are probably asking the wrong person. :-) But from what I have heard (apparently it has been discussed a number of times on the list), this should be possible using the HostWindowPlugin. But that's exactly the opposite way then I wanted to go here (move windows into, not out of Squeak) and I did not try out this plugin - not yet! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von gettimothy via Squeak-dev Gesendet: Mittwoch, 24. März 2021 19:50:25 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] X Server implementation for Squeak Do you need to do an 'xhost+" from the CLI to allow "foreign" windows to display? just grasping here... ---- On Wed, 24 Mar 2021 14:48:52 -0400 Thiede, Christoph wrote ---- Hi, sounds interesting. Does it still work for anyone in Trunk? I tried RFBServer start: 1 and then in a terminal $ DISPLAY=:1.0 xmessage foo but it said Error: Can't open display: :1.0 However, I got a Windows firewall warning so the image does indeed open a connection (and also starts a background process in the image). Did I miss anything? Apart from that, here are some more conceptual questions: How different are VNC and X11 actually? Afaik VNC is only used to stream entire screens while X11 is more fine-granular and allows to stream single windows. For what I proposed to do (use Morphic as a window manager), VNC would not suffice, would it? And how important is that difference from the implementational PoV? :-) Best, Christoph ________________________________ Von: Squeak-dev > im Auftrag von tim Rowledge > Gesendet: Mittwoch, 24. März 2021 19:27:18 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] X Server implementation for Squeak > On 2021-03-24, at 11:09 AM, Tobias Pape > wrote: > > Hi Christoph > >> On 24. Mar 2021, at 19:00, Thiede, Christoph > wrote: >> >> Hi all, >> >> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) > > There's RFB (aka VNC)… > It works surprisingly well… It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the http://source.squeak.org/ss repository - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Strange OpCodes: SVE: Skip on Vernal Equinox -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Wed Mar 24 19:08:10 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Wed, 24 Mar 2021 15:08:10 -0400 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: References: Message-ID: <20210324190810.GA73495@shell.msen.com> On Wed, Mar 24, 2021 at 06:00:16PM +0000, Thiede, Christoph wrote: > Hi all, > > > just an interested question: Is there any X Server implementation for > Squeak? I'm asking indeed not for an X Client implementation (I guess > that is what sqUnixX11.c and the HostWindowPlugin implementation for > Unix do) but for an X Server implementation, which could allow us to > manage arbitrary Unix windows in our Squeak Morphic world. Is there > already some solution like this? If not, anyone here who could make an > estimation about the effort for this? :-) > Hi Christoph, This is a really great question, and I'm happy to see it popping up from a certified MS-Windows guru :-) I think the idea has come up before once in a great while, and I certainly recall thinking about it myself a long time ago. I think the answer is yes. An X server is just another program that happens to understand the X11 protocols and know what to do with them. So you could, for example, start with the simplest possible open source X11 window manager that you can find, and reimplement its logic in Squeak. You would then install it as the X server. and from there you might start experimenting with rendering X11 client windows in Squeak. However, as a practical matter, this would be a big project. The protocols are complex, and modern X11 servers have accumulated a lot of fancy features that would be difficult to reproduce from scratch. Here is another way to look at it: Once apon a time, web browsers were simple and we had browser functionality written in Smalltalk, and running in the Squeak image. But as time went on, browsers got more complicated, and it became infeasible to keep up with the feature creep. I think you would find a similar situation with X11 servers. In theory you can write one, but it would be difficult to implement enough functionality to make it seem acceptable to users today. Dave From gettimothy at zoho.com Wed Mar 24 19:09:18 2021 From: gettimothy at zoho.com (gettimothy) Date: Wed, 24 Mar 2021 15:09:18 -0400 Subject: [squeak-dev] X Server implementation for Squeak Message-ID: <17865a4221a.11cfc5bf786385.9135710916431142838@zoho.com> Hi Christoph One more blind flail for the home team.. export DISPLAY=192.168.1.102:0.0 but replace the 192. stuff with something appropriate for your machine. Unfortunately, it did not help. I'm probably making things even more complicated by using WSL (Windows Subsystem for Linux) for my experiments ... However, together with VcXsrv, I am generally able to view WSL application in my Windows 10 desktop manager. I have read Eric S. Raymond on this....http://esr.ibiblio.org/?p=8764 I was thinking that Squeak may be able to ditch Windows builds completely and just do Linux/Mac/SunOS builds...someday. May make the VM team's life easier. > I would love to have Morphic windows display in my X Window Manager as regular X windows--like XTerm, XEyes..etc. That is independently of the Morphic world.>  > Do you think this is doable? You are probably asking the wrong person. :-) But from what I have heard (apparently it has been discussed a number of times on the list), this should be possible using the HostWindowPlugin. But that's exactly the opposite way then I wanted to go here (move windows into, not out of Squeak) and I did not try out this plugin -  not yet! :-) Best, Christoph Looking forward to it. I have two more nights of my 3'rd shift factory job and then I will be moving to first shift and this "should" free up my mind from the third shift blah's. so I can get some productive work in.  Wanna get Roassal done, then SqueakBooks workflow functional and then the OpenGL for Croquet and then...maybe I will have the chops for this task. I think an Emacs interface to Squeak would be the bees-knees too (: One step at a time, good luck with your XDisplay stuff.  Von: Squeak-dev im Auftrag von gettimothy via Squeak-dev Gesendet: Mittwoch, 24. März 2021 19:50:25 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] X Server implementation for Squeak   Do you need to do an 'xhost+"  from the CLI to allow "foreign" windows to display? just grasping here... ---- On Wed, 24 Mar 2021 14:48:52 -0400 Thiede, Christoph wrote ---- Hi, sounds interesting. Does it still work for anyone in Trunk? I tried RFBServer start: 1 and then in a terminal $ DISPLAY=:1.0 xmessage foo but it said Error: Can't open display: :1.0 http://www.hpi.de/ However, I got a Windows firewall warning so the image does indeed open a connection (and also starts a background process in the image). Did I miss anything? Apart from that, here are some more conceptual questions: How different are VNC and X11 actually? Afaik VNC is only used to stream entire screens while X11 is more fine-granular and allows to stream single windows. For what I proposed to do (use Morphic as a window manager), VNC would not suffice, would it? And how important is that difference from the implementational PoV? :-) Best, Christoph Von: Squeak-dev im Auftrag von tim Rowledge Gesendet: Mittwoch, 24. März 2021 19:27:18 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] X Server implementation for Squeak   > On 2021-03-24, at 11:09 AM, Tobias Pape wrote: > > Hi Christoph > >> On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: >> >> Hi all, >> >> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) > > There's RFB (aka VNC)… > It works surprisingly well… It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the http://source.squeak.org/ss repository  - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. tim -- tim Rowledge; mailto:tim at rowledge.org; http://www.rowledge.org/tim Strange OpCodes: SVE: Skip on Vernal Equinox -------------- next part -------------- An HTML attachment was scrubbed... URL: From tonyg at leastfixedpoint.com Wed Mar 24 19:13:34 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Wed, 24 Mar 2021 20:13:34 +0100 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: References: Message-ID: <05155adf-e67d-677f-f5b4-60f8cc008655@leastfixedpoint.com> On 3/24/21 7:00 PM, Thiede, Christoph wrote: > just an interested question: Is there any X Server implementation for > Squeak? A combination of this: https://gitlab.freedesktop.org/ofourdan/xcbproto and this: https://www.squeaksource.com/BitSyntax.html could be an interesting step towards getting a rudimentary X server running. I've implemented the client side of the X protocol before (in Scheme! It wasn't very pretty) but never the server side. Tony From eric.gade at gmail.com Wed Mar 24 19:40:00 2021 From: eric.gade at gmail.com (Eric Gade) Date: Wed, 24 Mar 2021 15:40:00 -0400 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: <17865a4221a.11cfc5bf786385.9135710916431142838@zoho.com> References: <17865a4221a.11cfc5bf786385.9135710916431142838@zoho.com> Message-ID: On Wed, Mar 24, 2021 at 3:09 PM gettimothy via Squeak-dev < squeak-dev at lists.squeakfoundation.org> wrote: > > I think an Emacs interface to Squeak would be the bees-knees too (: > > If you haven't heard about it, there's Shampoo ( https://revival.sh/shampoo/installation.html) which used to work for Pharo, but I haven't been able to get it running in a long time. Might have some good pointers there. -------------- next part -------------- An HTML attachment was scrubbed... URL: From tonyg at leastfixedpoint.com Wed Mar 24 20:14:24 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Wed, 24 Mar 2021 21:14:24 +0100 Subject: [squeak-dev] Self-style environments Message-ID: Hi all, In playing with Environments today, I found myself building a subclass of Environment with the following method in it: doesNotUnderstand: aMessage aMessage numArgs = 0 ifFalse: [^ super doesNotUnderstand: aMessage]. ^ self valueOf: aMessage selector ifAbsent: [ ^ super doesNotUnderstand: aMessage] Then, having constructed and set up some environment `e`, using the Browser to create classes X and Y in it, I can install it as a global: Smalltalk at: #E put: e and from then on I can say x := E X new. y := E Y new. etc. I can also do this recursively (and in fact cyclically, I think?). What's missing from this picture is tool support. In particular, Monticello support. I'd love to be able to have classes in my spliced-into-the-globals environment scanned by MC just like those in the toplevel. I've always found the MC codebase intimidating, however. Would it be reasonable to hope to be able to implement support for something like this in Monticello? Regards, Tony PS. squeak : unix :: Smalltalk globals : /, and it's just that Smalltalk globals, being a flat namespace, is equivalent to a DOS 1.0 root directory without subdirectory support. I guess I'm proposing adding subdirectories, bringing Squeak's file-system-analogue into the mid-80s DOS 2.0 era?? From vanessa at codefrau.net Wed Mar 24 20:29:41 2021 From: vanessa at codefrau.net (Vanessa Freudenberg) Date: Wed, 24 Mar 2021 13:29:41 -0700 Subject: [squeak-dev] Self-style environments In-Reply-To: References: Message-ID: On Wed, Mar 24, 2021 at 1:14 PM Tony Garnock-Jones < tonyg at leastfixedpoint.com> wrote: > What's missing from this picture is tool support. In particular, > Monticello support. I'd love to be able to have classes in my > spliced-into-the-globals environment scanned by MC just like those in > the toplevel. > > I've always found the MC codebase intimidating, however. Would it be > reasonable to hope to be able to implement support for something like > this in Monticello? > MC relies on PackageInfo to gather information about which definitions are in a package. Packages can provide their own PackageInfo subclass, and override the default behavior. See e.g. http://squeaksource.com/OMeta.html - Vanessa - -------------- next part -------------- An HTML attachment was scrubbed... URL: From leves at caesar.elte.hu Wed Mar 24 20:40:21 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Wed, 24 Mar 2021 21:40:21 +0100 (CET) Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: References: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de> Message-ID: Hi Tim, On Wed, 24 Mar 2021, tim Rowledge wrote: > > >> On 2021-03-24, at 11:09 AM, Tobias Pape wrote: >> >> Hi Christoph >> >>> On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: >>> >>> Hi all, >>> >>> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort for this? :-) >> >> There's RFB (aka VNC)… >> It works surprisingly well… > > It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the http://source.squeak.org/ss repository - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. I haven't used the RealVNC in years, but it used to work well back in the day with a few tweaks: IIRC you need to disable hexile and enable zrle and 24-bit colors. On linux, I can connect to Squeak RFB servers with Remmina[1] and Vinagre[2] without problems. I've been "maintaining" a fork of RFB[3]. Since the main repository is read-only, and Ian is not accessible, the current latest version is available here: http://leves.web.elte.hu/squeak/RFB-ul.19.mcz . Levente [1] https://remmina.org/ [2] https://wiki.gnome.org/Apps/Vinagre [3] http://leves.web.elte.hu/squeak/ > > > tim > -- > tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim > Strange OpCodes: SVE: Skip on Vernal Equinox From leves at caesar.elte.hu Wed Mar 24 20:42:51 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Wed, 24 Mar 2021 21:42:51 +0100 (CET) Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: <423a0f83ee0441be99a63cc20230373d@student.hpi.uni-potsdam.de> References: <3761C0D1-C402-4CCC-8B8F-ACA902728D46@gmx.de>, <423a0f83ee0441be99a63cc20230373d@student.hpi.uni-potsdam.de> Message-ID: Hi Christoph, On Wed, 24 Mar 2021, Thiede, Christoph wrote: > > Hi, > > > sounds interesting. Does it still work for anyone in Trunk? I tried > > RFBServer start: 1 > > and then in a terminal > > $ DISPLAY=:1.0 xmessage foo > > but it said > > Error: Can't open display: :1.0 An RFB server is not an X server, so that just won't work. Levente > > However, I got a Windows firewall warning so the image does indeed open a connection (and also starts a background process in the image). > Did I miss anything? > > Apart from that, here are some more conceptual questions: How different are VNC and X11 actually? Afaik VNC is only used to stream entire screens while X11 is more fine-granular and allows to stream single windows. For what I > proposed to do (use Morphic as a window manager), VNC would not suffice, would it? And how important is that difference from the implementational PoV? :-) > > Best, > Christoph > > _________________________________________________________________________________________________________________________________________________________________________________________________________________________________ > Von: Squeak-dev im Auftrag von tim Rowledge > Gesendet: Mittwoch, 24. März 2021 19:27:18 > An: The general-purpose Squeak developers list > Betreff: Re: [squeak-dev] X Server implementation for Squeak   > > > > On 2021-03-24, at 11:09 AM, Tobias Pape wrote: > > > > Hi Christoph > > > >> On 24. Mar 2021, at 19:00, Thiede, Christoph wrote: > >> > >> Hi all, > >> > >> just an interested question: Is there any X Server implementation for Squeak? I'm asking indeed not for an X Client implementation (I guess that is what sqUnixX11.c and the HostWindowPlugin implementation for Unix do) but > for an X Server implementation, which could allow us to manage arbitrary Unix windows in our Squeak Morphic world. Is there already some solution like this? If not, anyone here who could make an estimation about the effort > for this? :-) > > > > There's RFB (aka VNC)… > > It works surprisingly well… > > It does BUT it seems like it needs some updating to use some more modern protocols; I can connect to it from the RFB client in Squeak but not from the RealVNC client etc. The most up to date version(s) I know are in the > http://source.squeak.org/ss repository  - beware - there are what looks like two packages named RFB in there but the 'proper' one is 'RFB' and the other is actually ' RFB'. > > > tim > -- > tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim > Strange OpCodes: SVE: Skip on Vernal Equinox > > > > > From tim at rowledge.org Thu Mar 25 00:10:30 2021 From: tim at rowledge.org (tim Rowledge) Date: Wed, 24 Mar 2021 17:10:30 -0700 Subject: [squeak-dev] BitBlt performance work for ARM32 & 64 Message-ID: <8D641010-1D65-4E11-A4C7-EB95A3F30CE0@rowledge.org> We are *extremely* lucky that RPF has gifted us some of Ben Avison's time to revisit the BitBlt work he did in 2014 for the 32bit ARM vm in order to improve Scratch performance. Now he is going to work on extending that to support the 64bit ARM vm. He's asking for a bit of information though; - changes made to bitblt since then that might need attention. DIdn't we add a new rule or two some time back? - the choices about int/ptr for 64 bit. I could swear there was a doc explaining it somewhere on the github site but haven't spotted it yet tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Strange OpCodes: BIK: Buggered if I Know From lewis at mail.msen.com Thu Mar 25 01:15:38 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Wed, 24 Mar 2021 21:15:38 -0400 Subject: [squeak-dev] BitBlt performance work for ARM32 & 64 In-Reply-To: <8D641010-1D65-4E11-A4C7-EB95A3F30CE0@rowledge.org> References: <8D641010-1D65-4E11-A4C7-EB95A3F30CE0@rowledge.org> Message-ID: <20210325011538.GA24870@shell.msen.com> On Wed, Mar 24, 2021 at 05:10:30PM -0700, tim Rowledge wrote: > We are *extremely* lucky that RPF has gifted us some of Ben Avison's time to revisit the BitBlt work he did in 2014 for the 32bit ARM vm in order to improve Scratch performance. Now he is going to work on extending that to support the 64bit ARM vm. > Excellent! > He's asking for a bit of information though; > > - changes made to bitblt since then that might need attention. DIdn't we add a new rule or two some time back? I am not certain of the status in the VM, but I think these links provide the background: https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/505 http://source.squeak.org/VMMaker/VMMaker.oscog-nice.2909.diff Dave > - the choices about int/ptr for 64 bit. I could swear there was a doc explaining it somewhere on the github site but haven't spotted it yet > > tim > -- > tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim > Strange OpCodes: BIK: Buggered if I Know > > > From m at jaromir.net Thu Mar 25 08:15:58 2021 From: m at jaromir.net (Jaromir Matas) Date: Thu, 25 Mar 2021 03:15:58 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1616586593553-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> <1615901797162-0.post@n4.nabble.com> <1616011686241-0.post@n4.nabble.com> <1616586593553-0.post@n4.nabble.com> Message-ID: <1616660158843-0.post@n4.nabble.com> > Again from a rather conceptual point of view: How useful is it to terminate > a process "remotely", i.e. simulating it from the outside? > > Why can't we just activate the relevant return context > on the process (see #popTo:) and then resume it again? > > But conceptionally, wouldn't such > an approach be closer to the conceptual meaning of terminating a process? > > Just thinking aloud ... I'm looking forward to your opinion! :-) Hi Christoph, thanks! yes, I've been thinking along the same lines :) I think #runUntilErrorOrReturnFrom is not the cause of the problem though; #popTo is! It uses #evaluate:onBehalf:, the indirect way to unwind the terminated process. I still don't understand why we should want to unwind indirectly instead of just making the suspended process active and have it unwound itself... I created a new top context for it effectively sending it back to #terminate as an active process with the #activePriority, and replaced #popTo (and the remainder of #terminate) with: suspendedContext := Context sender: suspendedContext receiver: self method: (Process>>#terminate) arguments: {}. self priority: Processor activePriority. self resume. Processor yield See the whole #terminate method further below. All Process tests are green. It seems to resolve the 'easy' issues. Your non-local example seems to work as well with one caveat: It leaves the image with two UI processes, both in the prio 40 queue, alternating control. A question is: what is the semantics of the non-local return in [self error] ensure: [^2] or [self error] valueUninterruptably And I think it is exactly what it does now - it escapes the termination! I think it's called "cheating death"... A powerful and meaningful feature ;) #valueUninterruptably says: don't let *anything* interrupt me, not even a debugger Abandon. More precisesly: `self error` causes an error window is opened and a new UI process is spawned. Abandon then causes the new UI process sends #terminate to the previous UI process running the do-it. #terminate then makes the old UI execute #terminate on itself but during the unwind the non-local return (^2) causes both the unwind loop and #terminate are jumped over back to the original do-it and the old UI continues as if nothing happened :) The new UI, in the meantime, has finished closing the Error (debugger) window and continues it's everyday UI cycles. So we end up with two normal healthy UIs. Now my question is: how to remove the extra UI? One idea I haven't explored yet is why run a do-it withing the UI and not as a separate process? In this scenario the non-local return would continue or return from the do-it instead of returning inside the UI itself causing it survive the expected termination. But that's a big change. Would there be anything simpler? As for #runUntilErrorOrReturnFrom: I haven't studied it thorougly yet but my understanding is it's supposed to deal with unwind blocks caught in the middle of their unwinding - e.g. when abandoning the debugger (but I'd like to see some real examples first and I have to think about your remarks). As for #terminate: I had to do one modification the original unwind code: according to the N.B. note we do not set `complete` variable to true - but I can't see why: was a necessity for something or just saving a line? (I hope the latter but can get around the former too) >>> Why??? ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: >>> 2) to true." >>> ctxt tempAt: 2 put: true. "added, otherwise Abandon doesn't >>> work" Without it the debugger Abandon in this example [self error: 'e1'] ensure: [self error: 'e2'] wouldn't work: without the `complete` mark the Abandon (#windowIsClosing) sends #terminate, the process runs unwind, opens a debugger, Abandon sends #terminate etc. Process >> terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: >>> Why??? ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: >>> 2) to true." >>> ctxt tempAt: 2 put: true. "this is added otherwise Abandon >>> doesn't work" unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. thisContext terminateTo: nil. self suspend. "If the process is resumed this will provoke a cannotReturn: error. Would self debug: thisContext title: 'Resuming a terminated process' be better?" ^self]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. >>> suspendedContext := Context "now top context" sender: suspendedContext receiver: self method: (Process>>#terminate) arguments: {}. self priority: Processor activePriority. self resume. >>> Processor yield "important when using activePriority" ] > > > This scenario, however uncovers a weakness in the #isTerminated, > reporting > > the currently executing process with effectiveProcess assigned, as > > terminated and as a result preventing Process Browser to reveal such a > > pathological situation (which is precisely when you need to see it). > > I don't think so ... The violated invariant in this situation is that the > effectiveProcess variable has not been reset. In general, Process >> > #isTerminated should indeed consider the effectiveProcess. Debugging > "Processor activeProcess isTerminated" should always work exactly like > executing it outside the debugger. :-) > Yes, 100% agreed, but that's not the point I'm making :) I'm saying such a situation (where the effective process has not been reset) is rare but dangerous and we need to be aware of it rather sooner than later - i.e. for instance we need to see in the Process Browser there's one more process left - but now it's hiding as invisible because #isTerminated reports it as terminated. To demonstrate how dangerous the scenario is, do-it: [self error] ensure: [^2] and Abandon the ensuing Error window. Now the image becomes 'corrupted' or 'unstable' in the sense that the following do-it will hang the image: Semaphore new waitTimeoutMSecs: 50 If you try Test Runner the following Process and Semaphore tests fail and may even crash the image: testWaitTimeoutMSecs testProcessFaithfulSimulation testProcessFaithfulRunning testEvaluateOnBehalfOf The reason is after abandoning the error the following expressions are no longer true and some tests get confused: Processor activeProcess = Project current uiProcess "-> FALSE" Processor activeProcess = (Processor instVarNamed: 'genuineProcess') "-> FALSE" We can observe the anomaly indirectly by testing these expressions but what I'm suggesting is the Process Browser should be the place to reveal such a situation. To summarize: I admit such situations are rare so it's not a pressing issue. I look forward to your opinion about the #terminate experiment and the twin UI processes :) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From kksubbu.ml at gmail.com Thu Mar 25 10:53:35 2021 From: kksubbu.ml at gmail.com (K K Subbu) Date: Thu, 25 Mar 2021 16:23:35 +0530 Subject: [squeak-dev] X Server implementation for Squeak In-Reply-To: <20210324190810.GA73495@shell.msen.com> References: <20210324190810.GA73495@shell.msen.com> Message-ID: On 25/03/21 12:38 am, David T. Lewis wrote: > However, as a practical matter, this would be a big project. The protocols > are complex, and modern X11 servers have accumulated a lot of fancy > features that would be difficult to reproduce from scratch. > > Here is another way to look at it: Once apon a time, web browsers were > simple and we had browser functionality written in Smalltalk, and running > in the Squeak image. But as time went on, browsers got more complicated, > and it became infeasible to keep up with the feature creep. > > I think you would find a similar situation with X11 servers. In theory > you can write one, but it would be difficult to implement enough > functionality to make it seem acceptable to users today. Well said! Squeak hosts already have X display server software, so there is no incentive to build one for Squeak. Squeak makes more sense as a Xclient than an Xserver. There is an fascinating Squeak package called NetMorph circa 2002. Morphic objects could move along on a virtual display, like a multi-monitor video wall, spanning multiple Squeak nodes. It required a fast network and lots of RAM, so it may be a better fit for today's world. A NetMorphed Squeak image, running as Xclient on all nodes, can offer a much richer environment than just a plain display. Imagine live object migrations and collaborations! Sorry if this is off-topic. Regards .. Subbu From commits at source.squeak.org Thu Mar 25 12:41:24 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 25 Mar 2021 12:41:24 0000 Subject: [squeak-dev] The Inbox: Tools-tonyg.1033.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Tools to project The Inbox: http://source.squeak.org/inbox/Tools-tonyg.1033.mcz ==================== Summary ==================== Name: Tools-tonyg.1033 Author: tonyg Time: 25 March 2021, 1:41:22.140964 pm UUID: 904b0ec0-42f7-4ee7-9151-9b909132f7bd Ancestors: Tools-tonyg.1032 EXPERIMENTAL. EnvironmentBrowser class, to go alongside Environments-tonyg.78, which introduces nested `Namespace`s. =============== Diff against Tools-tonyg.1032 =============== Item was changed: - SystemOrganization addCategory: #'Tools-ArchiveViewer'! - SystemOrganization addCategory: #'Tools-Base'! - SystemOrganization addCategory: #'Tools-Browser'! - SystemOrganization addCategory: #'Tools-Changes'! SystemOrganization addCategory: #'Tools-Debugger'! + SystemOrganization addCategory: #'Tools-Changes'! + SystemOrganization addCategory: #'Tools-Inspector'! + SystemOrganization addCategory: #'Tools-MethodFinder'! - SystemOrganization addCategory: #'Tools-Explorer'! SystemOrganization addCategory: #'Tools-File Contents Browser'! SystemOrganization addCategory: #'Tools-FileList'! + SystemOrganization addCategory: #'Tools-Explorer'! - SystemOrganization addCategory: #'Tools-Inspector'! SystemOrganization addCategory: #'Tools-Menus'! + SystemOrganization addCategory: #'Tools-Browser'! + SystemOrganization addCategory: #'Tools-Base'! + SystemOrganization addCategory: #'Tools-ArchiveViewer'! - SystemOrganization addCategory: #'Tools-MethodFinder'! SystemOrganization addCategory: #'Tools-Process Browser'! Item was added: + Browser subclass: #EnvironmentBrowser + instanceVariableNames: 'environmentPath' + classVariableNames: '' + poolDictionaries: '' + category: 'Tools-Browser'! Item was added: + ----- Method: EnvironmentBrowser>>buildDefaultBrowserWith: (in category 'toolbuilder') ----- + buildDefaultBrowserWith: builder + | max windowSpec w | + max := self wantsOptionalButtons ifTrue:[0.42] ifFalse:[0.5]. + + windowSpec := self buildWindowWith: builder specs: { + (0 at 0 corner: 0.15 at max) -> [self buildEnvironmentTreeWith: builder]. + (0.15 at 0 corner: 0.35 at max) -> [self buildSystemCategoryListWith: builder]. + (self classListFrame: max fromLeft: 0.35 width: 0.25) -> [self buildClassListWith: builder]. + (self switchesFrame: max fromLeft: 0.35 width: 0.25) -> [self buildSwitchesWith: builder]. + (0.6 at 0 corner: 0.75 at max) -> [self buildMessageCategoryListWith: builder]. + (0.75 at 0 corner: 1 at max) -> [self buildMessageListWith: builder]. + (0 at max corner: 1 at 1) -> [self buildCodePaneWith: builder]. + }. + self setMultiWindowFor:windowSpec. + + w := builder build: windowSpec. + self changed: #expandRootsRequested. + ^ w! Item was added: + ----- Method: EnvironmentBrowser>>buildEnvironmentTreeWith: (in category 'namespace hierarchy') ----- + buildEnvironmentTreeWith: builder + | treeSpec | + treeSpec := builder pluggableTreeSpec new. + treeSpec + model: self ; + roots: #rootEnvironmentList; + hasChildren: #hasSubenvironments:; + getChildren: #subenvironmentsOf:; + setSelected: #selectEnvironment: ; + getSelected: #environment; + getSelectedPath: #environmentPath; + label: #subenvironmentNameOf: ; + menu: #environmentMenu: ; + autoDeselect: false. + ^ treeSpec + ! Item was added: + ----- Method: EnvironmentBrowser>>createSubenvironment (in category 'namespace hierarchy') ----- + createSubenvironment + | name e | + name := self promptForSafeName: 'What name should the new subenvironment have?'. + name ifNil: [^ self]. + e := Namespace withName: name. + e parent: environment. + self changed: #rootEnvironmentList. + self selectEnvironment: e. + ! Item was added: + ----- Method: EnvironmentBrowser>>defaultBrowserTitle (in category 'initialize-release') ----- + defaultBrowserTitle + ^ 'Environment Browser on ', self environment asString! Item was added: + ----- Method: EnvironmentBrowser>>environmentMenu: (in category 'namespace hierarchy') ----- + environmentMenu: aMenu + aMenu addList: #( + ('open workspace here' workspaceHere) + - + ). + aMenu + add: (environment isNamespace ifTrue: ['rename ...'] ifFalse: ['(cannot rename non-Namespace)']) + action: #renameEnvironment. + aMenu addList: #( + - + ('unlink environment' unlinkEnvironment) + ('create subenvironment' createSubenvironment) + ). + ^ aMenu + ! Item was added: + ----- Method: EnvironmentBrowser>>environmentPath (in category 'namespace hierarchy') ----- + environmentPath + ^ self environment namespacePath reversed! Item was added: + ----- Method: EnvironmentBrowser>>hasSubenvironments: (in category 'namespace hierarchy') ----- + hasSubenvironments: anEnvironment + ^ anEnvironment namespaces notEmpty! Item was added: + ----- Method: EnvironmentBrowser>>promptForSafeName: (in category 'namespace hierarchy') ----- + promptForSafeName: promptString + | name | + name := UIManager default request: promptString. + name ifEmpty: [^ nil]. + name := name asSymbol. + environment at: name ifPresent: [:existing | + self inform: 'That name already exists in the parent environment.'. + ^ nil]. + ^ name! Item was added: + ----- Method: EnvironmentBrowser>>renameEnvironment (in category 'namespace hierarchy') ----- + renameEnvironment + | name | + environment isNamespace ifFalse: [^ self]. + name := self promptForSafeName: 'What should the new name be?'. + name ifNil: [^ self]. + environment rename: name. + self changed: #rootEnvironmentList. + self selectEnvironment: environment.! Item was added: + ----- Method: EnvironmentBrowser>>rootEnvironmentList (in category 'namespace hierarchy') ----- + rootEnvironmentList + ^ Environment wellKnownInstances! Item was added: + ----- Method: EnvironmentBrowser>>selectEnvironment: (in category 'accessing') ----- + selectEnvironment: anEnvironment + super selectEnvironment: (anEnvironment ifNil: [self rootEnvironmentList first]). + self changed: #windowTitle. + self changed: #systemCategoryList. + self changed: #environment. + self changed: #selectedPath.! Item was added: + ----- Method: EnvironmentBrowser>>subenvironmentNameOf: (in category 'namespace hierarchy') ----- + subenvironmentNameOf: anEnvironment + ^ anEnvironment info name! Item was added: + ----- Method: EnvironmentBrowser>>subenvironmentsOf: (in category 'namespace hierarchy') ----- + subenvironmentsOf: anEnvironment + ^ anEnvironment namespaces! Item was added: + ----- Method: EnvironmentBrowser>>unlinkEnvironment (in category 'namespace hierarchy') ----- + unlinkEnvironment + | p | + p := environment parent. + p ifNotNil: [ + (self confirm: 'WARNING. You are about to delete an entire Environment!! Proceed?') + ifTrue: [ + environment parent: nil. + self selectEnvironment: p. + self changed: #rootEnvironmentList.]]! Item was added: + ----- Method: EnvironmentBrowser>>workspaceHere (in category 'namespace hierarchy') ----- + workspaceHere + Workspace new + environment: self environment; + openLabel: 'Workspace on environment ', self environment name! From commits at source.squeak.org Thu Mar 25 12:41:26 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Thu, 25 Mar 2021 12:41:26 0000 Subject: [squeak-dev] The Inbox: Environments-tonyg.78.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Environments to project The Inbox: http://source.squeak.org/inbox/Environments-tonyg.78.mcz ==================== Summary ==================== Name: Environments-tonyg.78 Author: tonyg Time: 25 March 2021, 1:41:26.338334 pm UUID: 1f57f26d-c9da-4c95-adb3-3fd76774a64d Ancestors: Environments-dtl.77 EXPERIMENTAL. Nested `Namespace`s, by introducing subclass Namespace of Environment, and placing Namespace instances as "globals" in their parent environment. See also Tools-tonyg.1033, which includes an experimental EnvironmentBrowser class. =============== Diff against Environments-dtl.77 =============== Item was changed: + SystemOrganization addCategory: #'Environments-Help'! SystemOrganization addCategory: #'Environments-Core'! SystemOrganization addCategory: #'Environments-Loading'! - SystemOrganization addCategory: #'Environments-Policies'! - SystemOrganization addCategory: #'Environments-Help'! SystemOrganization addCategory: #'Environments-Notifications'! + SystemOrganization addCategory: #'Environments-Policies'! + SystemOrganization addCategory: #'Environments-Namespaces'! Item was added: + ----- Method: Environment class>>wellKnownInstances (in category 'as yet unclassified') ----- + wellKnownInstances + ^ Instances values sorted: [:a :b | + (a info name = #Smalltalk) + ifTrue: [true] ifFalse: [ + (b info name = #Smalltalk) + ifTrue: [false] ifFalse: [ + a info name <= b info name]]]! Item was added: + ----- Method: Environment>>isNamespace (in category 'testing') ----- + isNamespace + ^ false! Item was added: + ----- Method: Environment>>namespacePath (in category 'accessing') ----- + namespacePath + ^ Array with: self! Item was added: + ----- Method: Environment>>namespaceTreeDo: (in category 'accessing') ----- + namespaceTreeDo: aBlock + aBlock value: self. + self namespaces do: [:ns | ns namespaceTreeDo: aBlock].! Item was added: + ----- Method: Environment>>namespaces (in category 'accessing') ----- + namespaces + "Answer all Environments declared here whose parent is this Environment" + | nss | + nss := self select: [:item | + (item value isKindOf: Environment) and: [item value parent == self]]. + nss := nss asArray collect: [:item | item value]. + nss sort: [:a :b | (a name compare: b name) <= 2]. + ^ nss! Item was added: + ----- Method: Environment>>parent (in category 'accessing') ----- + parent + ^ nil! Item was added: + ----- Method: Environment>>rename: (in category 'accessing') ----- + rename: newName + | wellKnown | + newName = info name ifTrue: [^ self]. + (wellKnown := Instances includes: self) ifTrue: [ + (Instances anySatisfy: [:e | newName = e info name]) + ifTrue: [self error: 'Name collision: well-known Environment with name ', newName, ' already exists']]. + wellKnown ifTrue: [Instances removeKey: info name]. + info rename: newName. + wellKnown ifTrue: [Instances at: newName put: self].! Item was added: + ----- Method: EnvironmentInfo>>rename: (in category 'private') ----- + rename: newName + name := newName! Item was added: + Environment subclass: #Namespace + instanceVariableNames: 'parent' + classVariableNames: '' + poolDictionaries: '' + category: 'Environments-Namespaces'! Item was added: + ----- Method: Namespace>>checkName:in: (in category 'namespace hierarchy') ----- + checkName: name in: parent + (parent notNil and: [(parent at: name ifAbsent: [self]) ~~ self]) + ifTrue: [self error: 'Name collision: proposed name ', name, ' in ', parent name, ' for namespace ', self name, ' is already taken'].! Item was added: + ----- Method: Namespace>>doesNotUnderstand: (in category 'dynamic lookup') ----- + doesNotUnderstand: aMessage + aMessage numArgs = 0 ifFalse: [^ super doesNotUnderstand: aMessage]. + ^ self valueOf: aMessage selector ifAbsent: [^ super doesNotUnderstand: aMessage]! Item was added: + ----- Method: Namespace>>initialize (in category 'initialize-release') ----- + initialize + super initialize. + self importSelf. + self import: Environment default.! Item was added: + ----- Method: Namespace>>isNamespace (in category 'as yet unclassified') ----- + isNamespace + ^ true! Item was added: + ----- Method: Namespace>>namespacePath (in category 'namespace hierarchy') ----- + namespacePath + | e | + e := self. + ^ (Array streamContents: [:w | + [e notNil and: [e isNamespace]] whileTrue: [ + w nextPut: e. + e := e parent]]) reverseInPlace! Item was added: + ----- Method: Namespace>>parent (in category 'accessing') ----- + parent + ^ parent! Item was added: + ----- Method: Namespace>>parent: (in category 'accessing') ----- + parent: anEnvironment + | n | + parent == anEnvironment ifTrue: [^self]. + n := info name asSymbol. + self checkName: n in: anEnvironment. + parent ifNotNil: [parent removeKey: n]. + parent := anEnvironment. + parent ifNotNil: [parent at: n put: self].! Item was added: + ----- Method: Namespace>>printOn: (in category 'printing') ----- + printOn: aStream + self namespacePath do: [:n | aStream nextPutAll: n info name] separatedBy: [aStream space]! Item was added: + ----- Method: Namespace>>rename: (in category 'accessing') ----- + rename: newName + | p | + p := parent. + self checkName: newName in: p. + self parent: nil. + super rename: newName. + self parent: p.! Item was added: + ----- Method: Namespace>>respondsTo: (in category 'dynamic lookup') ----- + respondsTo: aSymbol + ^ (super respondsTo: aSymbol) or: [self includesKey: aSymbol]! From tonyg at leastfixedpoint.com Thu Mar 25 12:58:34 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Thu, 25 Mar 2021 13:58:34 +0100 Subject: [squeak-dev] EnvironmentBrowser and nested Namespaces (was Re: The Inbox: Environments-tonyg.78.mcz) In-Reply-To: References: Message-ID: <8de91609-2662-2bda-6771-c05cc095aee8@leastfixedpoint.com> Hi all, This message is about the in-inbox EXPERIMENTAL DRAFT packages - http://source.squeak.org/inbox/Environments-tonyg.78.mcz and - http://source.squeak.org/inbox/Tools-tonyg.1033.mcz The two packages go together. Screenshot of EnvironmentBrowser in action attached. The idea here is a kind of Self-like "namespacing" facility, based around placing Environment instances into another Environment's globals table. The EnvironmentBrowser class in Tools 1033 is a sketch of UI for the core functionality I've identified so far. If I have the following setup of nested Environments... Smalltalk -- the normal Environment default / Environment current - A - B - C - D with class X in A, class Y in B, a *different* class Y in C, and class Z in D, then - In a workspace whose environment is Smalltalk, `A` evaluates to the environment A. `A B` evaluates to the environment B. `A B Y` evaluates to B's Y. `A C Y` evaluates to C's Y. etc. - In a workspace whose environment is A, all of the examples from the Smalltalk paragraph above are unchanged `B` evaluates to the environment B, `B Y` yields B's Y `C Y` yields C's Y `D` is an undefined name - In a workspace whose environment is B, all of the examples from the Smalltalk paragraph above are unchanged `Y` is B's Y `C` and `D` are undefined names The ability of Environments to import/export is unused (!) at present, other than Namespace instances default to importing self and Smalltalk. I'm looking at Monticello now. The major difficulty is that it hardcodes `Environment current` and expects a single environment to apply. I imagine the following: - the nested namespaces are analogous to nested folders in a Unix file system - packages are like Debian packages, and may have entries in multiple namespaces - `Environment current` at load time acts like a chroot Given those guesses/assumptions, MC might need to learn about the idea of classes living in a particular (or more than one!) Environment, and the necessity of creating Namespaces as needed. Here's an interesting method on PackageInfo I've been messing around with: classesAndEnvironments | cs | cs := IdentityDictionary new. self systemCategories do: [:cat | Environment current namespaceTreeDo: [:environment | (environment organization listAtCategoryNamed: cat) do: [:className | | envs | envs := cs at: (environment valueOf: className) ifAbsentPut: [Set new]. envs add: environment]]]. ^ cs Does anyone have thoughts on this whole approach? On how MC's model could profitably be altered to include a notion of namespace/environment? Regards, Tony -------------- next part -------------- A non-text attachment was scrubbed... Name: Environment Browser on E F: NamespacedExampleClass.png Type: image/png Size: 39836 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: Workspace on environment E F.png Type: image/png Size: 10583 bytes Desc: not available URL: From tonyg at leastfixedpoint.com Thu Mar 25 12:59:31 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Thu, 25 Mar 2021 13:59:31 +0100 Subject: [squeak-dev] Self-style environments In-Reply-To: References: Message-ID: <7184f3d0-5961-a00f-dfc1-da37c3035109@leastfixedpoint.com> On 3/24/21 9:29 PM, Vanessa Freudenberg wrote: > MC relies on PackageInfo to gather information about which definitions > are in a package. > > Packages can provide their own PackageInfo subclass, and override the > default behavior. Thanks, Vanessa! That's helpful. I think, to my chagrin :-) , that I'm already well outside what the core MC model can offer... but if I'm wrong about that, that would be great! Tony From tonyg at leastfixedpoint.com Thu Mar 25 14:44:44 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Thu, 25 Mar 2021 15:44:44 +0100 Subject: [squeak-dev] Squeak Board election for 2021? Message-ID: Hello all, Did I miss the Board election this year? Regards, Tony From vanessa at codefrau.net Thu Mar 25 17:20:54 2021 From: vanessa at codefrau.net (Vanessa Freudenberg) Date: Thu, 25 Mar 2021 10:20:54 -0700 Subject: [squeak-dev] Self-style environments In-Reply-To: <7184f3d0-5961-a00f-dfc1-da37c3035109@leastfixedpoint.com> References: <7184f3d0-5961-a00f-dfc1-da37c3035109@leastfixedpoint.com> Message-ID: On Thu, Mar 25, 2021 at 5:59 AM Tony Garnock-Jones < tonyg at leastfixedpoint.com> wrote: > On 3/24/21 9:29 PM, Vanessa Freudenberg wrote: > > MC relies on PackageInfo to gather information about which definitions > > are in a package. > > > > Packages can provide their own PackageInfo subclass, and override the > > default behavior. > > Thanks, Vanessa! That's helpful. > > I think, to my chagrin :-) , that I'm already well outside what the core > MC model can offer... but if I'm wrong about that, that would be great! > Your PI subclass just needs to answer what classes and methods are considered to be in your package. What else do you need? - Vanessa - -------------- next part -------------- An HTML attachment was scrubbed... URL: From tonyg at leastfixedpoint.com Thu Mar 25 18:09:04 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Thu, 25 Mar 2021 19:09:04 +0100 Subject: [squeak-dev] Self-style environments In-Reply-To: References: <7184f3d0-5961-a00f-dfc1-da37c3035109@leastfixedpoint.com> Message-ID: On 3/25/21 6:20 PM, Vanessa Freudenberg wrote: > Your PI subclass just needs to answer what classes and methods are > considered to be in your package. What else do you need? They need to be attached to the correct Environment on load, too. So the package needs to know something about Environments other than Environment current. From Das.Linux at gmx.de Thu Mar 25 18:10:17 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Thu, 25 Mar 2021 19:10:17 +0100 Subject: [squeak-dev] Self-style environments In-Reply-To: References: <7184f3d0-5961-a00f-dfc1-da37c3035109@leastfixedpoint.com> Message-ID: <6BF26390-844D-454C-912E-FA7F5850AE9A@gmx.de> HI > On 25. Mar 2021, at 19:09, Tony Garnock-Jones wrote: > > On 3/25/21 6:20 PM, Vanessa Freudenberg wrote: >> Your PI subclass just needs to answer what classes and methods are considered to be in your package. What else do you need? > > They need to be attached to the correct Environment on load, too. So the package needs to know something about Environments other than Environment current. I think Jakob had a bit more tooling, no? BEst -Tobias From forums.jakob at resfarm.de Thu Mar 25 20:42:09 2021 From: forums.jakob at resfarm.de (Jakob Reschke) Date: Thu, 25 Mar 2021 21:42:09 +0100 Subject: [squeak-dev] Self-style environments In-Reply-To: <0f48e87fe14e4f588007f1a9cb5bdaa5@MX2018-DAG2.hpi.uni-potsdam.de> References: <7184f3d0-5961-a00f-dfc1-da37c3035109@leastfixedpoint.com> <0f48e87fe14e4f588007f1a9cb5bdaa5@MX2018-DAG2.hpi.uni-potsdam.de> Message-ID: Hi, I had sprinkled menu items around some tools (like the MCSnapshotBrowser) that were labelled something like "Load into other environment...", which would prompt you for the environment, then make it the "Environment current" during the loading. I have lost track though how many of these I have submitted to the Inbox or how many have been merged in Trunk and which were not. One of these menu items is "change environment..." on a package in the Monticello Browser. It would change the environment of an MCWorkingCopy for future snapshots and loads. Also all my modifications kept Environments out of the package definitions. In terms of Tony's experiment: you would need your special environment with doesNotUnderstand: already set up, then make it the "Environment current" while you load the package in order to get it back as Tony had intended it to be. For example, create the (empty) package in the Monticello browser, then "change environment" of it to your special environment, then load the package from a repository. If you would not do this and load as usual instead, it would load into Smalltalk globals instead, regardless of how Tony had saved it. Kind regards, Jakob Am Do., 25. März 2021 um 19:10 Uhr schrieb Tobias Pape : > HI > > > > On 25. Mar 2021, at 19:09, Tony Garnock-Jones > wrote: > > > > On 3/25/21 6:20 PM, Vanessa Freudenberg wrote: > >> Your PI subclass just needs to answer what classes and methods are > considered to be in your package. What else do you need? > > > > They need to be attached to the correct Environment on load, too. So the > package needs to know something about Environments other than Environment > current. > > I think Jakob had a bit more tooling, no? > > BEst > -Tobias > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tim at rowledge.org Thu Mar 25 23:13:45 2021 From: tim at rowledge.org (tim Rowledge) Date: Thu, 25 Mar 2021 16:13:45 -0700 Subject: [squeak-dev] BitBlt performance work for ARM32 & 64 In-Reply-To: <20210325011538.GA24870@shell.msen.com> References: <8D641010-1D65-4E11-A4C7-EB95A3F30CE0@rowledge.org> <20210325011538.GA24870@shell.msen.com> Message-ID: <7DFA8808-8821-4ED0-B96C-C4A499363E21@rowledge.org> > On 2021-03-24, at 6:15 PM, David T. Lewis wrote: > > I am not certain of the status in the VM, but I think these links provide the background: > > https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/505 > > http://source.squeak.org/VMMaker/VMMaker.oscog-nice.2909.diff OK, passed them on. Ben is clearly having a fun time with this. His test suite has 524288 tests! Right now he's down to just 6 failing, all relating to addWord/subWord stuff, specifically when the line length takes up less than a word. Hell, rather than trying to edit I'll just include his comments - > The next problem I hit appears to be a genuine bug in the existing code - specifically the function rgbComponentAlphawith() - one which has simply become more visible due to a buffer overrun fix in copyLoop(). > > What's happening is that source and destination images are 8 bpp, but the source and destination positions differ in 32-bit word alignment. Yet 32-bit blocks of pixels are passed in and out of rgbComponentAlphawith(), aligned to words at the destination. Therefore in a case like the following: > > Word boundaries at source | | | > Pixels X X X X X X X > Word boundaries at dest | | | | > > previously, copyLoop() would read from the word following the last source pixel when constructing the final source word to pass to rgbComponentAlphawith() - but this is unsafe if the last source pixel is at the end of the image and the image ends at memory page alignment, because the following page might not be mapped in. The new version of copyLoop() correctly skips this load; however, it arbitrarily chooses to zero the relevant bits instead, and this triggers a shortcut in rgbComponentAlphawith() to be taken when it wasn't before. > > This shortcut leaves the destination word unchanged if the source word was all 0. At first glance this seems OK, since even at < 32bpp, the source pixels are made up of bitfields, and for a component alpha operation, each field is used as an alpha weight to blend a planar colour into the destination. The problem is in the way the blend calculation is done: it's (dest * (0xFF - alpha) + planar_source * alpha) >> 8. Thus when alpha == 0, it will subtract 1 from each colour component value. It was particularly noticeable in my test because it also utilised random gamma tables, so the off-by-one value was very stark. > > Ideally, the blending algorithm would be fixed so that an alpha of 0 leaves the destination unchanged. However, in all but a straight-through 1:1 gamma LUT, there will still be at least some incidences of a many-to-one mapping, so a round trip through gamma and ungamma could cause colour component changes even with an alpha of 0 and a better blending algorithm. So the simple solution is to remove the invalid shortcut in rgbComponentAlphawith(), and once you do so, the old and new builds produce the same result for this test. The change does impact the results of some other tests too, so I needed to recalculate the correct CRCs with this change in place. > > By now I was down to 190 failing tests out of 524288. Surveying the first 10, their combinationRules are all either addWord or subWord. Bearing the above in mind, I immediately suspected what the problem might be. Since pixels are stored left-to-right in most-significant-to-least-significant order, and carry/borrow propagate from less-significant to more-significant bits, that means that memory locations after the nominal end of the source row can impact the result. That means that the change that zeroes the remaining bits rather than loading them has the potential to change the results whenever word-relative alignment differs between source and destination. > > This time I tried backporting the buffer overflow fix to the old build (it's a good thing not to read off the end of the input buffer in any case) and recalculating the CRCs again. > > Now we were down to 6 failures out of 524288 tests. They were all addWord or subWord again, but the extra distinguishing feature this time was that the line lengths were very short - no more than 1 pixel for 16bpp, 3 pixels for 8bpp and (though there weren't enough examples to prove it) presumably no more than 7 pixels for 4bpp and so on. > > After a bit more digging, I think this change is responsible: > https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/426 > > in the sense that it also causes bits that are outside the positions that are masked into the destination to be zeroed when they weren't before, but in such a way that they affect whether or not a carry or borrow into bit positions that *do* matter happens. > > Unfortunately the patch from the resolution of that issue doesn't cleanly apply back onto the old source tree - it seems there were other intervening changes in how the "preload" flag was calculated. However, I'm reasonably confident that since there are now only 6 failures, they're probably all caused by this one remaining issue. It's very reassuring that I now get the same results from the new source tree irrespective of whether the 32-bit ARM assembly fast paths are enabled or not. So the easiest thing is to simply recalculate the CRCs again from the new source tree and use them as a baseline for the AArch64 conversion. > > One thing that occurs to me is that, given that there are some combinationRules that have this "leaking across pixel boundaries" behaviour (and maybe it might be deliberately added one day - say for a "blur" operation) it arguably should be the case that the source and destination words are masked to only include the bits relating to pixels included in the bounding box *before* calling the combinationRule as well as afterwards. For example, assuming an operation on a single 8bpp pixel: > > Words at source |AA AA AA AA|BB BB BB BB| > Pixel ** > Words at destination |FF FF FF FF| > > In the old Squeak VM, addWordwith() would have been passed 0xAAAAAABB and 0xFFFFFFFF. New VMs skip the load of the second source word and pass 0xAAAAAA00 and 0xFFFFFFFF. What I'm saying is, perhaps it should be 0x00AA0000 and 0x00FF0000 instead. (Had this rule been in place already, none of the issues I hit today would have shown up.) Anything anyone can think of that might help would be appreciated. Although the intent here is to make the ARM64 system as fast as possible for Pi benefit, it will have probably benefits for other machine because some of his improvements are just C code. Bug fixes should be passed up to all systems easily enough. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim At the end of the day, a cliché walks into a bar -- fresh as a daisy, cute as a button, and sharp as a tack. From marcel.taeumel at hpi.de Fri Mar 26 10:31:04 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 26 Mar 2021 11:31:04 +0100 Subject: [squeak-dev] Self-style environments In-Reply-To: References: Message-ID: Hi Tony, thanks for playing around with Environments. :-)  As Jakob described, there are tools already supporting #environment when looking up class names. Try browsing all implementors of #environment. As you mentioned, your initial example with "x := E X new" proposes a syntax that does not exist at the moment. Given that, for some reason, you want to put an environment into a global #E one would need to write: x := (E classNamed: #X) new. Of course, you could shorten this by adding #doesNotUnderstand: to Environment. In general, the class "Environment" organizes named environments already: x := ((Environment named: #MyProject) classNamed: #X) new. Provided that classes know their environment, there might be no need to write such code in methods. Just in workspaces for experimentation. Yet, environments are not organized in a hierarchy, which means that look up will not fall back: (Environment named: #Example) classNamed: #String. "nil" Anyway, I don't follow your comparison with the DOS 1.0 file system. At least that motivation does not work for me. :-) In a regular application, I would never want to explicate an environment name in my classes' methods. Instead, the correct environment should remain implicit. Maybe like a "working directory"? :-D Ha, maybe now I get your metaphor... Best, Marcel Am 24.03.2021 21:14:32 schrieb Tony Garnock-Jones : Hi all, In playing with Environments today, I found myself building a subclass of Environment with the following method in it: doesNotUnderstand: aMessage aMessage numArgs = 0 ifFalse: [^ super doesNotUnderstand: aMessage]. ^ self valueOf: aMessage selector ifAbsent: [ ^ super doesNotUnderstand: aMessage] Then, having constructed and set up some environment `e`, using the Browser to create classes X and Y in it, I can install it as a global: Smalltalk at: #E put: e and from then on I can say x := E X new. y := E Y new. etc. I can also do this recursively (and in fact cyclically, I think?). What's missing from this picture is tool support. In particular, Monticello support. I'd love to be able to have classes in my spliced-into-the-globals environment scanned by MC just like those in the toplevel. I've always found the MC codebase intimidating, however. Would it be reasonable to hope to be able to implement support for something like this in Monticello? Regards, Tony PS. squeak : unix :: Smalltalk globals : /, and it's just that Smalltalk globals, being a flat namespace, is equivalent to a DOS 1.0 root directory without subdirectory support. I guess I'm proposing adding subdirectories, bringing Squeak's file-system-analogue into the mid-80s DOS 2.0 era?? -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Fri Mar 26 10:42:24 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 26 Mar 2021 11:42:24 +0100 Subject: [squeak-dev] EnvironmentBrowser and nested Namespaces (was Re: The Inbox: Environments-tonyg.78.mcz) In-Reply-To: <8de91609-2662-2bda-6771-c05cc095aee8@leastfixedpoint.com> References: <8de91609-2662-2bda-6771-c05cc095aee8@leastfixedpoint.com> Message-ID: Hi Tony, if I would implement a hierarchy of environments, I would not exploit "globals" or "declarations" but add "outer" and/or "inner" as instance variables. Then #classNamed: needs to be changed to also look in outer environments. -- I think that environments are already "namespaces". Thus, I would not add an extra subclass "Namespace" for it.  The second proposal in here is that new syntax via #doesNotUnderstand:. Hmm... I do not like it. :-) Maybe a Environment class >> #fromPath: would work. Then tools can support such a path syntax. In source code I would rather not use it to not create any more "spaghetti code" than we already have. Feels like a "pandoras box" to allow an easy way for arbitrary environments in any piece of code. Best, Marcel Am 25.03.2021 13:58:51 schrieb Tony Garnock-Jones : Hi all, This message is about the in-inbox EXPERIMENTAL DRAFT packages - http://source.squeak.org/inbox/Environments-tonyg.78.mcz and - http://source.squeak.org/inbox/Tools-tonyg.1033.mcz The two packages go together. Screenshot of EnvironmentBrowser in action attached. The idea here is a kind of Self-like "namespacing" facility, based around placing Environment instances into another Environment's globals table. The EnvironmentBrowser class in Tools 1033 is a sketch of UI for the core functionality I've identified so far. If I have the following setup of nested Environments... Smalltalk -- the normal Environment default / Environment current - A - B - C - D with class X in A, class Y in B, a *different* class Y in C, and class Z in D, then - In a workspace whose environment is Smalltalk, `A` evaluates to the environment A. `A B` evaluates to the environment B. `A B Y` evaluates to B's Y. `A C Y` evaluates to C's Y. etc. - In a workspace whose environment is A, all of the examples from the Smalltalk paragraph above are unchanged `B` evaluates to the environment B, `B Y` yields B's Y `C Y` yields C's Y `D` is an undefined name - In a workspace whose environment is B, all of the examples from the Smalltalk paragraph above are unchanged `Y` is B's Y `C` and `D` are undefined names The ability of Environments to import/export is unused (!) at present, other than Namespace instances default to importing self and Smalltalk. I'm looking at Monticello now. The major difficulty is that it hardcodes `Environment current` and expects a single environment to apply. I imagine the following: - the nested namespaces are analogous to nested folders in a Unix file system - packages are like Debian packages, and may have entries in multiple namespaces - `Environment current` at load time acts like a chroot Given those guesses/assumptions, MC might need to learn about the idea of classes living in a particular (or more than one!) Environment, and the necessity of creating Namespaces as needed. Here's an interesting method on PackageInfo I've been messing around with: classesAndEnvironments | cs | cs := IdentityDictionary new. self systemCategories do: [:cat | Environment current namespaceTreeDo: [:environment | (environment organization listAtCategoryNamed: cat) do: [:className | | envs | envs := cs at: (environment valueOf: className) ifAbsentPut: [Set new]. envs add: environment]]]. ^ cs Does anyone have thoughts on this whole approach? On how MC's model could profitably be altered to include a notion of namespace/environment? Regards, Tony -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 26 11:37:03 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 11:37:03 0000 Subject: [squeak-dev] The Trunk: System-mt.1223.mcz Message-ID: Marcel Taeumel uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-mt.1223.mcz ==================== Summary ==================== Name: System-mt.1223 Author: mt Time: 26 March 2021, 12:36:58.297513 pm UUID: a5df7ebb-e1e7-304c-85e5-61d01132f0bd Ancestors: System-mt.1222 Adds hook to browse environments. =============== Diff against System-mt.1222 =============== Item was added: + ----- Method: ToolSet class>>browseEnvironment: (in category 'browsing') ----- + browseEnvironment: anEnvironment + + self default ifNil: [^ self inform: 'Cannot open Browser']. + ^ self default browseEnvironment: anEnvironment! From commits at source.squeak.org Fri Mar 26 11:38:21 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 11:38:21 0000 Subject: [squeak-dev] The Trunk: Tools-mt.1033.mcz Message-ID: Marcel Taeumel uploaded a new version of Tools to project The Trunk: http://source.squeak.org/trunk/Tools-mt.1033.mcz ==================== Summary ==================== Name: Tools-mt.1033 Author: mt Time: 26 March 2021, 12:38:18.607513 pm UUID: 04055581-eafa-8d43-a839-e487634ad4e1 Ancestors: Tools-tonyg.1032 Complements System-mt.1223. Adds hook to browse environments. =============== Diff against Tools-tonyg.1032 =============== Item was added: + ----- Method: Browser class>>fullOnEnvironment: (in category 'instance creation') ----- + fullOnEnvironment: anEnvironment + + ^ self new + selectEnvironment: anEnvironment; + buildAndOpenFullBrowser! Item was added: + ----- Method: Environment>>browse (in category '*Tools-Browsing') ----- + browse + + ^ ToolSet browseEnvironment: self! Item was added: + ----- Method: StandardToolSet class>>browseEnvironment: (in category 'browsing') ----- + browseEnvironment: anEnvironment + + ^ SystemBrowser default fullOnEnvironment: anEnvironment! From marcel.taeumel at hpi.de Fri Mar 26 11:41:45 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 26 Mar 2021 12:41:45 +0100 Subject: [squeak-dev] ToolSet and Environments (was Re: The Trunk: Tools-tonyg.1032.mcz) In-Reply-To: <1c482d79-a8c1-07cf-dd73-15cd93eb89dc@leastfixedpoint.com> References: <1c482d79-a8c1-07cf-dd73-15cd93eb89dc@leastfixedpoint.com> Message-ID: Hi Tony. > Is it intended to be a kind of registry of available in-image Environments? Yes, looks similar to PackageOrganizer. > Would some thinking about how to surface those in the tooling be welcome? Yes, indeed. :-) I just added ToolSet cass >> #browseEnvironment: and Environment >> #browse to Trunk. And I noticed that something seems to be missing from empty environments since I cannot compile a new class into it through the Browser. Not even "Smalltalk" as a global can be resovled -- even though it is in "declarations". Maybe Environment >> #initializeWithName: is not correct? Have fun! :-) Best, Marcel Am 24.03.2021 16:40:28 schrieb Tony Garnock-Jones : Hi all, I've been experimenting with Environments a little. They look promising, but if I understand correctly we don't have much in the way of tool support for them yet? Would a patch to ToolSet be welcome to add, say, `browseEnvironment:` and a convenience `Environment >> browse` to the various ToolSets? It took a little digging before I found (Browser new selectEnvironment: someEnvironment) buildAndOpenFullBrowser Further than that, there seems not to be many users of Environment's class-side Instances variable yet. Is it intended to be a kind of registry of available in-image Environments? Would some thinking about how to surface those in the tooling be welcome? Tony On 3/24/21 3:36 PM, commits at source.squeak.org wrote: > Tony Garnock-Jones uploaded a new version of Tools to project The Trunk: > http://source.squeak.org/trunk/Tools-tonyg.1032.mcz > > ==================== Summary ==================== > > Name: Tools-tonyg.1032 > Author: tonyg > Time: 24 March 2021, 4:36:27.132139 pm > UUID: 1077d608-e946-49dd-99f0-3a55ffe06e81 > Ancestors: Tools-mt.1031 > > Repair Browser to allow selection of classes in non-default Environments. > > =============== Diff against Tools-mt.1031 =============== > > Item was changed: > ----- Method: Browser>>addTrait (in category 'traits') ----- > addTrait > | input trait | > input := UIManager default request: 'add trait'. > input isEmptyOrNil ifFalse: [ > + trait := self environment classNamed: input. > - trait := Smalltalk classNamed: input. > (trait isNil or: [trait isTrait not]) ifTrue: [ > ^self inform: 'Input invalid. ' , input , ' does not exist or is not a trait']. > self selectedClass setTraitComposition: self selectedClass traitComposition asTraitComposition + trait. > self contentsChanged]. > ! > > Item was changed: > ----- Method: Browser>>hasClassSelected (in category 'class list') ----- > hasClassSelected > + ^ selectedClassName notNil and: [(self environment classNamed: selectedClassName) notNil]! > - ^ selectedClassName notNil and: [(Smalltalk classNamed: selectedClassName) notNil]! > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 26 11:51:22 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 11:51:22 0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1383.mcz Message-ID: Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1383.mcz ==================== Summary ==================== Name: Kernel-mt.1383 Author: mt Time: 26 March 2021, 12:51:18.904073 pm UUID: 524a87b1-28d6-f044-8a9a-4ca045211ac1 Ancestors: Kernel-ct.1382 Merges Kernel-ct.1382 =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + [value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! From commits at source.squeak.org Fri Mar 26 11:51:53 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 11:51:53 0000 Subject: [squeak-dev] The Trunk: Kernel-ct.1382.mcz Message-ID: Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-ct.1382.mcz ==================== Summary ==================== Name: Kernel-ct.1382 Author: ct Time: 15 March 2021, 1:52:03.249869 pm UUID: e108423f-661f-4d4f-9ad8-c667c3995b32 Ancestors: Kernel-mt.1381 Proposal: Revises usage and handling of primitive 19, also known as the simulation guard. Don't use it in #newProcess and variants since they don't involve any actual control logic. Instead, also show a simulation warning when debugging a control primitive (primitiveSignal primitiveWait primitiveResume primitiveSuspend). Improves integration of simulation guard warnings by signaling a Warning on the simulator stack rather than spawning a debugger on the debugged process. This also makes it easier to handle these warnings in a non-interactive context. See http://forum.world.st/Simulation-guard-lt-primitive-19-gt-crashes-the-image-td5127443.html and http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-code-simulation-td5127684.html for more information. Reuploaded to resolve merge conflict with Kernel-mt.1381. Replaces Kernel-ct.1381, which can be moved into the treated inbox. =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + ["Transcript + cr; + nextPutAll: 'Processor activeProcess '; + nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]); + nextPutAll: ' owner'; + flush." + value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! From ron at usmedrec.com Fri Mar 26 13:24:10 2021 From: ron at usmedrec.com (Ron Teitelbaum) Date: Fri, 26 Mar 2021 09:24:10 -0400 Subject: [squeak-dev] Squeak Board election for 2021? In-Reply-To: References: Message-ID: Hi Tony, No you didn't miss the election I did. We are working on it. There will be an update soon. Ron On Thu, Mar 25, 2021, 10:44 AM Tony Garnock-Jones wrote: > Hello all, > > Did I miss the Board election this year? > > Regards, > Tony > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 26 15:44:27 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 26 Mar 2021 15:44:27 +0000 Subject: [squeak-dev] The Trunk: Kernel-mt.1383.mcz In-Reply-To: References: Message-ID: <15d53d6252714068a49d76a473db40b9@student.hpi.uni-potsdam.de> Thank you, Marcel! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von commits at source.squeak.org Gesendet: Freitag, 26. März 2021 12:51 Uhr An: squeak-dev at lists.squeakfoundation.org; packages at lists.squeakfoundation.org Betreff: [squeak-dev] The Trunk: Kernel-mt.1383.mcz Marcel Taeumel uploaded a new version of Kernel to project The Trunk: http://source.squeak.org/trunk/Kernel-mt.1383.mcz ==================== Summary ==================== Name: Kernel-mt.1383 Author: mt Time: 26 March 2021, 12:51:18.904073 pm UUID: 524a87b1-28d6-f044-8a9a-4ca045211ac1 Ancestors: Kernel-ct.1382 Merges Kernel-ct.1382 =============== Diff against Kernel-mt.1381 =============== Item was changed: ----- Method: BlockClosure>>newProcess (in category 'scheduling') ----- newProcess + "Answer a Process running the code in the receiver. The process is not scheduled." - "Answer a Process running the code in the receiver. The process is not - scheduled." - "Simulation guard" ^Process forContext: [self value. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: BlockClosure>>newProcessWith: (in category 'scheduling') ----- newProcessWith: anArray + "Answer a Process running the code in the receiver. The receiver's block arguments are bound to the contents of the argument, anArray. The process is not scheduled." - "Answer a Process running the code in the receiver. The receiver's block - arguments are bound to the contents of the argument, anArray. The - process is not scheduled." - "Simulation guard" ^Process forContext: [self valueWithArguments: anArray. + "Since control is now at the bottom, there is no need to terminate (which runs unwinds) since all unwinds have been run. Simply suspend. + Note that we must use this form rather than e.g. Processor suspendActive so that isTerminated answers true. isTerminated requires that if there is a suspended context it is the bottom-most, but using a send would result in the process's suspendedContext /not/ being the bottom-most." - "Since control is now at the bottom there is no need to terminate (which - runs unwinds) since all unwnds have been run. Simply suspend. - Note that we must use this form rather than e.g. Processor suspendActive - so that isTerminated answers true. isTerminated requires that if there is a - suspended context it is the bottom-most, but using a send would result in - the process's suspendedContext /not/ being the bottom-most." Processor activeProcess suspend] asContext priority: Processor activePriority! Item was changed: ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') ----- doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments "Simulate a primitive method whose index is primitiveIndex. The simulated receiver and arguments are given as arguments to this message. If successful, push result and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes execution needs to be intercepted and simulated to avoid execution running away." | value | "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents the debugger from entering various run-away activities such as spawning a new process, etc. Injudicious use results in the debugger not being able to debug interesting code, such as the debugger itself. Hence use primitive 19 with care :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]" + (primitiveIndex = 19 or: [primitiveIndex >= 85 and: [primitiveIndex <= 88] "control primitives"]) ifTrue: [ - primitiveIndex = 19 ifTrue: [ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})] ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]]. ((primitiveIndex between: 201 and: 222) and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue: [(primitiveIndex = 206 or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: arguments first caller: self]. ((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]" or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver simulateValueWithArguments: arguments caller: self]]. primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]" [^self send: arguments first to: receiver with: arguments allButFirst]. primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)]. primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:" [^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)]. "Mutex>>primitiveEnterCriticalSection Mutex>>primitiveTestAndSetOwnershipOfCriticalSection" (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue: + [value := primitiveIndex = 186 + ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess] + ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess]. - [| effective | - effective := Processor activeProcess effectiveProcess. - "active == effective" - value := primitiveIndex = 186 - ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective] - ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]]. primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod: CompiledMethod class>>receiver:withArguments:executeMethod: VMMirror>>ifFail:object:with:executeMethod: et al" [| n args methodArg thisReceiver | ((n := arguments size) between: 2 and: 4) ifFalse: [^self class primitiveFailTokenFor: #'unsupported operation']. ((self objectClass: (args := arguments at: n - 1)) == Array and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse: [^self class primitiveFailTokenFor: #'bad argument']. methodArg numArgs = args size ifFalse: [^self class primitiveFailTokenFor: #'bad number of arguments']. thisReceiver := arguments at: n - 2 ifAbsent: [receiver]. methodArg primitive > 0 ifTrue: [methodArg isQuick ifTrue: [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)]. ^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args]. ^Context sender: self receiver: thisReceiver method: methodArg arguments: args]. primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM" [(arguments size = 3 and: [(self objectClass: arguments second) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifTrue: [^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last]. (arguments size = 2 and: [(self objectClass: arguments first) == SmallInteger and: [(self objectClass: arguments last) == Array]]) ifFalse: [^self class primitiveFailTokenFor: nil]. ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last]. value := primitiveIndex = 120 "FFI method" ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments] ifFalse: [primitiveIndex = 117 "named primitives" ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments] ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)" [receiver tryPrimitive: primitiveIndex withArgs: arguments]]. ^(self isPrimFailToken: value) ifTrue: [value] ifFalse: [self push: value]! -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits at source.squeak.org Fri Mar 26 16:37:48 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 16:37:48 0000 Subject: [squeak-dev] The Inbox: Environments-tonyg.79.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Environments to project The Inbox: http://source.squeak.org/inbox/Environments-tonyg.79.mcz ==================== Summary ==================== Name: Environments-tonyg.79 Author: tonyg Time: 26 March 2021, 5:37:48.213254 pm UUID: 653dd6de-a4d9-4656-8d2e-4e5d5dcf3803 Ancestors: Environments-tonyg.78 EXPERIMENTAL. Builds on .78 to offer a little more reflection on Environments, suitable for use by tooling (see forthcoming Tools-tonyg.1034). =============== Diff against Environments-tonyg.78 =============== Item was added: + ----- Method: Environment>>allSubNamespaces (in category 'accessing') ----- + allSubNamespaces + ^ Array streamContents: [:s | self namespaceTreeDo: [:ns | s nextPut: ns]]! Item was added: + ----- Method: Environment>>exports (in category 'accessing') ----- + exports + "TODO this is gross - can we think of something better?" + | temp | + temp := Environment withName: #temp. + temp import: self. + ^ temp provisions! Item was added: + ----- Method: Environment>>policies (in category 'accessing') ----- + policies + ^ policies! Item was added: + ----- Method: Environment>>removePolicy: (in category 'accessing') ----- + removePolicy: policy + policies := policies copyWithout: policy! From commits at source.squeak.org Fri Mar 26 16:39:13 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 16:39:13 0000 Subject: [squeak-dev] The Inbox: Tools-tonyg.1034.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Tools to project The Inbox: http://source.squeak.org/inbox/Tools-tonyg.1034.mcz ==================== Summary ==================== Name: Tools-tonyg.1034 Author: tonyg Time: 26 March 2021, 5:39:11.891811 pm UUID: 351a3901-163a-4ccf-a9a2-2892c91e2ae1 Ancestors: Tools-tonyg.1033, Tools-mt.1033 EXPERIMENTAL. Merge from trunk, and add UI support for managing import/export policies of Environments in EnvironmentBrowser. =============== Diff against Tools-tonyg.1033 =============== Item was added: + ----- Method: AddPrefixNamePolicy>>description (in category '*Tools-Browsing') ----- + description + ^ '* -> ', prefix, '*'! Item was added: + ----- Method: AllNamePolicy>>description (in category '*Tools-Browsing') ----- + description + ^ '*'! Item was added: + ----- Method: BindingPolicy>>description (in category '*Tools-Browsing') ----- + description + "It'd be nice to be a bit more explicit about this, rather than having + to infer importishness/exportishness by looking at the addSelector" + | pol | + pol := '(', policy description, ')'. + ^ addSelector caseOf: { + [#notifyObserversOfBindingAdded:] -> ['export ', pol]. + [#showBinding:] -> ['import ', environment printString, ' ', pol]. + } otherwise: ['[?] ', environment printString, ' ', pol]! Item was added: + ----- Method: Browser class>>fullOnEnvironment: (in category 'instance creation') ----- + fullOnEnvironment: anEnvironment + + ^ self new + selectEnvironment: anEnvironment; + buildAndOpenFullBrowser! Item was added: + ----- Method: Environment>>browse (in category '*Tools-Browsing') ----- + browse + + ^ ToolSet browseEnvironment: self! Item was changed: Browser subclass: #EnvironmentBrowser + instanceVariableNames: 'environmentPath importExportIndex' - instanceVariableNames: 'environmentPath' classVariableNames: '' poolDictionaries: '' category: 'Tools-Browser'! Item was changed: ----- Method: EnvironmentBrowser>>buildDefaultBrowserWith: (in category 'toolbuilder') ----- buildDefaultBrowserWith: builder | max windowSpec w | max := self wantsOptionalButtons ifTrue:[0.42] ifFalse:[0.5]. windowSpec := self buildWindowWith: builder specs: { + (0 at 0 corner: 0.15 at 0.3) -> [self buildEnvironmentTreeWith: builder]. + (0 at 0.3 corner: 0.35 at max) -> [self buildEnvironmentImportExportListWith: builder]. + (0.15 at 0 corner: 0.35 at 0.3) -> [self buildSystemCategoryListWith: builder]. - (0 at 0 corner: 0.15 at max) -> [self buildEnvironmentTreeWith: builder]. - (0.15 at 0 corner: 0.35 at max) -> [self buildSystemCategoryListWith: builder]. (self classListFrame: max fromLeft: 0.35 width: 0.25) -> [self buildClassListWith: builder]. (self switchesFrame: max fromLeft: 0.35 width: 0.25) -> [self buildSwitchesWith: builder]. (0.6 at 0 corner: 0.75 at max) -> [self buildMessageCategoryListWith: builder]. (0.75 at 0 corner: 1 at max) -> [self buildMessageListWith: builder]. (0 at max corner: 1 at 1) -> [self buildCodePaneWith: builder]. }. self setMultiWindowFor:windowSpec. w := builder build: windowSpec. self changed: #expandRootsRequested. ^ w! Item was added: + ----- Method: EnvironmentBrowser>>buildEnvironmentImportExportListWith: (in category 'as yet unclassified') ----- + buildEnvironmentImportExportListWith: builder + | listSpec | + listSpec := builder pluggableListSpec new. + listSpec + model: self; + list: #importExportList; + getIndex: #importExportIndex; + setIndex: #importExportIndex:; + menu: #importExportMenu:. + ^listSpec + ! Item was changed: ----- Method: EnvironmentBrowser>>environmentMenu: (in category 'namespace hierarchy') ----- environmentMenu: aMenu aMenu addList: #( ('open workspace here' workspaceHere) - ). aMenu add: (environment isNamespace ifTrue: ['rename ...'] ifFalse: ['(cannot rename non-Namespace)']) action: #renameEnvironment. aMenu addList: #( + ('explore environment' exploreEnvironment) - ('unlink environment' unlinkEnvironment) ('create subenvironment' createSubenvironment) ). ^ aMenu ! Item was added: + ----- Method: EnvironmentBrowser>>exploreEnvironment (in category 'as yet unclassified') ----- + exploreEnvironment + self environment explore! Item was added: + ----- Method: EnvironmentBrowser>>importExportExplore (in category 'as yet unclassified') ----- + importExportExplore + (self environment policies at: importExportIndex) explore! Item was added: + ----- Method: EnvironmentBrowser>>importExportExportAddingPrefix (in category 'as yet unclassified') ----- + importExportExportAddingPrefix + | p | + p := UIManager default request: 'Prefix to add?'. + p ifNotEmpty: [ + self environment exportAddingPrefix: p. + self changed: #importExportList]! Item was added: + ----- Method: EnvironmentBrowser>>importExportExportRemovingPrefix (in category 'as yet unclassified') ----- + importExportExportRemovingPrefix + | p | + p := UIManager default request: 'Prefix to filter by and then remove?'. + p ifNotEmpty: [ + self environment exportRemovingPrefix: p. + self changed: #importExportList]! Item was added: + ----- Method: EnvironmentBrowser>>importExportExportSelf (in category 'as yet unclassified') ----- + importExportExportSelf + self environment exportSelf! Item was added: + ----- Method: EnvironmentBrowser>>importExportExportSpecific (in category 'as yet unclassified') ----- + importExportExportSpecific + (self requestNamesFrom: self environment title: 'Names to export') ifNotNil: [:names | + self environment export: names. + self changed: #importExportList]! Item was added: + ----- Method: EnvironmentBrowser>>importExportImportAddingPrefix (in category 'as yet unclassified') ----- + importExportImportAddingPrefix + self requestEnvironment: [:e | | p | + p := UIManager default request: 'Prefix to add?'. + p ifNotEmpty: [ + self environment import: e addingPrefix: p. + self changed: #importExportList]]! Item was added: + ----- Method: EnvironmentBrowser>>importExportImportAll (in category 'as yet unclassified') ----- + importExportImportAll + self requestEnvironment: [:e | + self environment import: e. + self changed: #importExportList]! Item was added: + ----- Method: EnvironmentBrowser>>importExportImportRemovingPrefix (in category 'as yet unclassified') ----- + importExportImportRemovingPrefix + self requestEnvironment: [:e | | p | + p := UIManager default request: 'Prefix to filter by and then remove?'. + p ifNotEmpty: [ + self environment import: e removingPrefix: p. + self changed: #importExportList]]! Item was added: + ----- Method: EnvironmentBrowser>>importExportImportSelf (in category 'as yet unclassified') ----- + importExportImportSelf + self environment importSelf! Item was added: + ----- Method: EnvironmentBrowser>>importExportImportSpecific (in category 'as yet unclassified') ----- + importExportImportSpecific + self requestEnvironment: [:e | + (self requestNamesFrom: e title: 'Names to import') ifNotNil: [:names | + self environment from: e import: names. + self changed: #importExportList]]! Item was added: + ----- Method: EnvironmentBrowser>>importExportIndex (in category 'as yet unclassified') ----- + importExportIndex + ^ importExportIndex ifNil: [0]! Item was added: + ----- Method: EnvironmentBrowser>>importExportIndex: (in category 'as yet unclassified') ----- + importExportIndex: newIndex + importExportIndex := newIndex. + self changed: #importExportIndex! Item was added: + ----- Method: EnvironmentBrowser>>importExportList (in category 'as yet unclassified') ----- + importExportList + ^ self environment policies collect: [:p | p description]! Item was added: + ----- Method: EnvironmentBrowser>>importExportMenu: (in category 'as yet unclassified') ----- + importExportMenu: aMenu + aMenu addList: #( + ('import all from self' importExportImportSelf) + ('import all from environment' importExportImportAll) + ('import all from environment, adding prefix' importExportImportAddingPrefix) + ('import prefixed from environment, removing prefix' importExportImportRemovingPrefix) + ('import specific names from environment' importExportImportSpecific) + - + ('export all' importExportExportSelf) + ('export all, adding prefix' importExportExportAddingPrefix) + ('export prefixed, removing prefix' importExportExportRemovingPrefix) + ('export specific names' importExportExportSpecific) + - + ('remove policy' importExportRemove) + - + ('explore policy' importExportExplore) + ). + ^ aMenu! Item was added: + ----- Method: EnvironmentBrowser>>importExportRemove (in category 'as yet unclassified') ----- + importExportRemove + self environment removePolicy: (self environment policies at: importExportIndex). + self changed: #importExportList! Item was added: + ----- Method: EnvironmentBrowser>>requestEnvironment: (in category 'as yet unclassified') ----- + requestEnvironment: aBlock + | nss | + nss := Environment wellKnownInstances gather: [:ns | ns allSubNamespaces]. + (UIManager default + chooseFrom: (nss collect: [:ns | ns printString]) + values: nss + lines: #() + title: 'Select an environment') ifNotNil: aBlock! Item was added: + ----- Method: EnvironmentBrowser>>requestNamesFrom:title: (in category 'as yet unclassified') ----- + requestNamesFrom: env title: title + | allNames | + allNames := env exports sort. + ^ (UIManager default chooseMultipleFrom: allNames values: allNames title: title)! Item was changed: ----- Method: EnvironmentBrowser>>selectEnvironment: (in category 'accessing') ----- selectEnvironment: anEnvironment super selectEnvironment: (anEnvironment ifNil: [self rootEnvironmentList first]). self changed: #windowTitle. self changed: #systemCategoryList. self changed: #environment. + self changed: #selectedPath. + self changed: #importExportList.! - self changed: #selectedPath.! Item was added: + ----- Method: ExplicitNamePolicy>>description (in category '*Tools-Browsing') ----- + description + ^ String streamContents: [:s | + (aliases associations + collect: [:a | a key = a value ifTrue: [a key asString] ifFalse: [a printString]]) + sort joinOn: s separatedBy: ', ']! Item was added: + ----- Method: NamePolicy>>description (in category '*Tools-Browsing') ----- + description + self subclassResponsibility! Item was added: + ----- Method: RemovePrefixNamePolicy>>description (in category '*Tools-Browsing') ----- + description + ^ prefix, '* -> *'! Item was added: + ----- Method: StandardToolSet class>>browseEnvironment: (in category 'browsing') ----- + browseEnvironment: anEnvironment + + ^ SystemBrowser default fullOnEnvironment: anEnvironment! From tonyg at leastfixedpoint.com Fri Mar 26 17:03:06 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Fri, 26 Mar 2021 18:03:06 +0100 Subject: [squeak-dev] Self-style environments In-Reply-To: References: Message-ID: <19328027-3f37-26b4-a2ff-c70bcc29b1a3@leastfixedpoint.com> Hi Marcel, (I'll bundle your replies into one here.) On 3/26/21 11:31 AM, Marcel Taeumel wrote: > thanks for playing around with Environments. :-) It's fun! And also I need it, or at least I *think* I need it, for a compiler for a data-describing schema language. The use of prefixes is getting horribly horribly unwieldy, so short *relative* names make more sense to me than long *absolute*(ish) names. > Of course, you could [allow syntax like E A X new etc] by adding #doesNotUnderstand: to > Environment. This is exactly what the Namespace subclass of Environment does. Well, Namespace does three things that plain Environment doesn't, and arguably shouldn't, do: - #doesNotUnderstand: to act ergonomically, like Self modules - configuring self with a small but sensible set of initial imports, namely importSelf and import: Environment default - managing a "parent" relationship to another environment, and enforcing naming invariants wrt the entry for self in that parent's binding table. > environments are not organized in a hierarchy, > which means that look up will not fall back: Yes, and I think this is the correct behaviour. The existing import/export mechanism is I think better than a hierarchical lookup system. The hierarchy of namespaces comes in when you want to explicitly refer to something unusual, something not managed via the normal Environment import/export mechanism. The usual stuff, like Array, String etc., would be imported and so available directly in the local Environment as usual. > Anyway, I don't follow your comparison with the DOS 1.0 file system. Just that Smalltalk's globals are analogous to the root directory of a file system, and that like DOS 1.0 and unlike unix, it's a flat, structureless collection of names. > In a regular > application, I would never want to explicate an environment name in > my classes' methods. Me neither. The overwhelming majority of name usage is of *relative* identifiers. Absolute naming is, ultimately, impossible :-) but also not a very good idea. > Instead, the correct environment should remain > implicit. Maybe like a "working directory"? :-D Ha, maybe now I get > your metaphor... Heh, yes quite. So this is how Environments already work, ISTM: most name references are relative, to the active Environment. My proposal (? it's not really a proposal yet, more just an experiment) is to add hierarchical reference to Environments to allow for nonlocal reference when needed. As an example, my schema compiler, done with absolute names, generates monsters like this: PreservesSchemaCompoundPattern subclass: #'PreservesSchemaCompoundPattern_setof' "..." And that's just for the meta-schema! When it comes to real schemas, I often have multiple that "import" definitions from one another, leading to names like NovySyndicateSturdyCaveat_Rewrite referencing NovySyndicateActorRef etc. I'd very much like to be able to write PreservesSchema CompoundPattern setof instead. But classes aren't "higher-order" in the right way to have the obvious way of doing that work. So Environments was where I ended up looking. Perhaps I'm looking under the lamp, where the light is brightest? Is there some dark corner of the system where I should be directing my attention? I'd love to hear about it! On 3/26/21 11:42 AM, Marcel Taeumel wrote: > if I would implement a hierarchy of environments, I would not exploit > "globals" or "declarations" but add "outer" and/or "inner" as > instance variables. Then #classNamed: needs to be changed to also > look in outer environments. I prefer the way Environments work now, with explicit imports and exports to manage the local namespace, and with no particular hierarchy enforced. The Namespace idea/quasiproposal adds just one other thing: reachability of classes in other environments from some root environment using a path, for those situations where an import is inappropriate. I guess it also adds tooling support which would be, uh, *difficult* without some kind of hierarchy. Marcel, I'd love to hear your thoughts on the EnvironmentBrowser experiment in the inbox. I'll post again in a minute with a summary of where I'm up to with it. On 3/26/21 12:41 PM, Marcel Taeumel wrote: > Yes, indeed. :-) I just added ToolSet cass >> #browseEnvironment: > and Environment >> #browse to Trunk. Thank you for those! Much appreciated. > And I noticed that something > seems to be missing from empty environments since I cannot compile a > new class into it through the Browser. Yes, you have to import: Environment default to get the base declarations into scope. I think the "Smalltalk" and "Undeclared" entries are red herrings, but I haven't gotten into the details yet to understand them properly. > Maybe > Environment >> #initializeWithName: is not correct? I think it's correct. Once you add importSelf and import: Environment default to a new environment, things work fine in the Browser. Best Regards, and thanks again for the responses, Tony From commits at source.squeak.org Fri Mar 26 18:05:00 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Fri, 26 Mar 2021 18:05:00 0000 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz Message-ID: A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-mt.932.mcz ==================== Summary ==================== Name: Collections-mt.932 Author: mt Time: 26 March 2021, 7:04:57.368373 pm UUID: b6c0c2c9-0a4f-684c-87a7-069813edd154 Ancestors: Collections-dtl.931 Sketch of a dictionary that has collections as values. dict := CollectionsDictionary new. (dict at: #fruits) addAll: #(apple apple peach). (dict at: #sweets) add: #nougat. dict removeKey: #sweets. dict explore. =============== Diff against Collections-dtl.931 =============== Item was added: + Dictionary subclass: #CollectionsDictionary + instanceVariableNames: 'collectionClass' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Unordered'! Item was added: + ----- Method: CollectionsDictionary class>>defaultCollectionClass (in category 'defaults') ----- + defaultCollectionClass + + ^ OrderedCollection! Item was added: + ----- Method: CollectionsDictionary class>>newOnBags (in category 'instance creation') ----- + newOnBags + + ^ self new + setCollectionClass: Bag; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnOrderedCollections (in category 'instance creation') ----- + newOnOrderedCollections + + ^ self new + setCollectionClass: OrderedCollection; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnSets (in category 'instance creation') ----- + newOnSets + + ^ self new + setCollectionClass: Set; + yourself! Item was added: + ----- Method: CollectionsDictionary>>at: (in category 'accessing') ----- + at: key + + ^ self at: key ifAbsent: [super at: key put: collectionClass new]! Item was added: + ----- Method: CollectionsDictionary>>at:put: (in category 'accessing') ----- + at: key put: value + + self shouldNotImplement.! Item was added: + ----- Method: CollectionsDictionary>>collectionClass (in category 'accessing') ----- + collectionClass + + ^ collectionClass! Item was added: + ----- Method: CollectionsDictionary>>initialize: (in category 'initialization') ----- + initialize: n + + super initialize: n. + self setCollectionClass: self class defaultCollectionClass.! Item was added: + ----- Method: CollectionsDictionary>>setCollectionClass: (in category 'initialization') ----- + setCollectionClass: aClass + + collectionClass := aClass.! From marcel.taeumel at hpi.de Fri Mar 26 18:08:44 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 26 Mar 2021 19:08:44 +0100 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: References: Message-ID: Hi all! What do you think? Does it makes sense to pursue this idea of "dictionaries with collections as values" and enrich it with tests and documentation? Best, Marcel Am 26.03.2021 19:05:09 schrieb commits at source.squeak.org : A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-mt.932.mcz ==================== Summary ==================== Name: Collections-mt.932 Author: mt Time: 26 March 2021, 7:04:57.368373 pm UUID: b6c0c2c9-0a4f-684c-87a7-069813edd154 Ancestors: Collections-dtl.931 Sketch of a dictionary that has collections as values. dict := CollectionsDictionary new. (dict at: #fruits) addAll: #(apple apple peach). (dict at: #sweets) add: #nougat. dict removeKey: #sweets. dict explore. =============== Diff against Collections-dtl.931 =============== Item was added: + Dictionary subclass: #CollectionsDictionary + instanceVariableNames: 'collectionClass' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Unordered'! Item was added: + ----- Method: CollectionsDictionary class>>defaultCollectionClass (in category 'defaults') ----- + defaultCollectionClass + + ^ OrderedCollection! Item was added: + ----- Method: CollectionsDictionary class>>newOnBags (in category 'instance creation') ----- + newOnBags + + ^ self new + setCollectionClass: Bag; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnOrderedCollections (in category 'instance creation') ----- + newOnOrderedCollections + + ^ self new + setCollectionClass: OrderedCollection; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnSets (in category 'instance creation') ----- + newOnSets + + ^ self new + setCollectionClass: Set; + yourself! Item was added: + ----- Method: CollectionsDictionary>>at: (in category 'accessing') ----- + at: key + + ^ self at: key ifAbsent: [super at: key put: collectionClass new]! Item was added: + ----- Method: CollectionsDictionary>>at:put: (in category 'accessing') ----- + at: key put: value + + self shouldNotImplement.! Item was added: + ----- Method: CollectionsDictionary>>collectionClass (in category 'accessing') ----- + collectionClass + + ^ collectionClass! Item was added: + ----- Method: CollectionsDictionary>>initialize: (in category 'initialization') ----- + initialize: n + + super initialize: n. + self setCollectionClass: self class defaultCollectionClass.! Item was added: + ----- Method: CollectionsDictionary>>setCollectionClass: (in category 'initialization') ----- + setCollectionClass: aClass + + collectionClass := aClass.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 26 18:50:29 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 26 Mar 2021 18:50:29 +0000 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: References: , Message-ID: Hi Marcel, I'm a bit afraid of creating more subclasses of Collection or Dictionary for two reasons: 1. Different subclasses are incompatible. If you wanted a special dictionary that has weak keys and holds collections, you would need to create another subclass and duplicate some of the logic. 2. Such a design change could introduce ambivalence and doubts about what subclass to choose, and if you choose the wrong class, you will need to do additional conversions. For example, should Collection >> #groupBy: return CollectionsDictionary instances with your proposal? If there is any other legacy code that does not use CollectionsDictionary, you will need to check or fix its type to avoid DNUs when further logic might be added to CollectionsDictionary later. Sometimes I have the feeling that the approach of creating too many collection/dictionary subclasses could violate the idea of polymorphy because they effectively remove genericity from their subclasses and refuse a lot of bequest (e.g., the math functions protocol from Collection). That being said, I'm not completely against the idea, but these are some common concerns I have on collection subclassing in general. I would like to avoid ending up with a convoluted design such as .NET has, which contains next to the generic List: StringList, StringCollection, StringDictionary, ListCollection, IntCollection, etc. ... :-) Hypothetically, an alternative approach would be to add a new protocol to an existing superclass, for example 'list enumerating' on Dictionary, which would provide for compatibility with other data structures. For example, existing items could even be wrapped into a list when doing something like: myDict at: #fruits put: #apple. (myDict makeListAt: #fruits) addAll: #(banana cherry date). (myDict makeListAt: #sweets) add: 'eclair; add: 'froyo'; add: 'gingerbread'. See Collection >> #associationsDo: for another example. What do you think about it? :-) However, these are only my 2 cents without a clear opinion. Looking forward to your arguments! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Freitag, 26. März 2021 19:08 Uhr An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz Hi all! What do you think? Does it makes sense to pursue this idea of "dictionaries with collections as values" and enrich it with tests and documentation? Best, Marcel Am 26.03.2021 19:05:09 schrieb commits at source.squeak.org : A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-mt.932.mcz ==================== Summary ==================== Name: Collections-mt.932 Author: mt Time: 26 March 2021, 7:04:57.368373 pm UUID: b6c0c2c9-0a4f-684c-87a7-069813edd154 Ancestors: Collections-dtl.931 Sketch of a dictionary that has collections as values. dict := CollectionsDictionary new. (dict at: #fruits) addAll: #(apple apple peach). (dict at: #sweets) add: #nougat. dict removeKey: #sweets. dict explore. =============== Diff against Collections-dtl.931 =============== Item was added: + Dictionary subclass: #CollectionsDictionary + instanceVariableNames: 'collectionClass' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Unordered'! Item was added: + ----- Method: CollectionsDictionary class>>defaultCollectionClass (in category 'defaults') ----- + defaultCollectionClass + + ^ OrderedCollection! Item was added: + ----- Method: CollectionsDictionary class>>newOnBags (in category 'instance creation') ----- + newOnBags + + ^ self new + setCollectionClass: Bag; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnOrderedCollections (in category 'instance creation') ----- + newOnOrderedCollections + + ^ self new + setCollectionClass: OrderedCollection; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnSets (in category 'instance creation') ----- + newOnSets + + ^ self new + setCollectionClass: Set; + yourself! Item was added: + ----- Method: CollectionsDictionary>>at: (in category 'accessing') ----- + at: key + + ^ self at: key ifAbsent: [super at: key put: collectionClass new]! Item was added: + ----- Method: CollectionsDictionary>>at:put: (in category 'accessing') ----- + at: key put: value + + self shouldNotImplement.! Item was added: + ----- Method: CollectionsDictionary>>collectionClass (in category 'accessing') ----- + collectionClass + + ^ collectionClass! Item was added: + ----- Method: CollectionsDictionary>>initialize: (in category 'initialization') ----- + initialize: n + + super initialize: n. + self setCollectionClass: self class defaultCollectionClass.! Item was added: + ----- Method: CollectionsDictionary>>setCollectionClass: (in category 'initialization') ----- + setCollectionClass: aClass + + collectionClass := aClass.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From tonyg at leastfixedpoint.com Fri Mar 26 19:01:04 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Fri, 26 Mar 2021 20:01:04 +0100 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: References: Message-ID: <89cceb33-75b8-1ea3-a68d-105effc8f121@leastfixedpoint.com> On 3/26/21 7:08 PM, Marcel Taeumel wrote: > What do you think? Does it makes sense to pursue this idea of > "dictionaries with collections as values" and enrich it with tests and > documentation? I frequently use dictionaries mapping keys to sets of values. I rely often on these invariants: - retrieval of a not-present key yields an empty collection - removal of all the items from a given key's collection automatically removes the key as well I've never needed 'size' to yield anything other than the number of keys. Christoph's concerns about interface/implementation explosion are well-founded, though, I reckon; do... do we still have traits in Squeak? Cheers, Tony From marcel.taeumel at hpi.de Fri Mar 26 19:03:24 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 26 Mar 2021 20:03:24 +0100 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: References: <,> Message-ID: Hi Christoph, thanks for the comments. I think that some of your comments address problems with Dictionary or the collection hierarchy in general.  This proposal is just about avoiding the following: (myDict at: #fruits ifAbsentPut: [OrderedCollection new]) add: #apple. Best, Marcel Am 26.03.2021 19:50:40 schrieb Thiede, Christoph : Hi Marcel, I'm a bit afraid of creating more subclasses of Collection or Dictionary for two reasons: 1. Different subclasses are incompatible. If you wanted a special dictionary that has weak keys and holds collections, you would need to create another subclass and duplicate some of the logic. 2. Such a design change could introduce ambivalence and doubts about what subclass to choose, and if you choose the wrong class, you will need to do additional conversions. For example, should Collection >> #groupBy: return CollectionsDictionary instances with your proposal? If there is any other legacy code that does not use CollectionsDictionary, you will need to check or fix its type to avoid DNUs when further logic might be added to CollectionsDictionary later. Sometimes I have the feeling that the approach of creating too many collection/dictionary subclasses could violate the idea of polymorphy because they effectively remove genericity from their subclasses and refuse a lot of bequest (e.g., the math functions protocol from Collection). That being said, I'm not completely against the idea, but these are some common concerns I have on collection subclassing in general. I would like to avoid ending up with a convoluted design such as .NET has, which contains next to the generic List: StringList, StringCollection, StringDictionary, ListCollection, IntCollection, etc. ... :-) Hypothetically, an alternative approach would be to add a new protocol to an existing superclass, for example 'list enumerating' on Dictionary, which would provide for compatibility with other data structures. For example, existing items could even be wrapped into a list when doing something like: myDict at: #fruits put: #apple. (myDict makeListAt: #fruits) addAll: #(banana cherry date). (myDict makeListAt: #sweets) add: 'eclair; add: 'froyo'; add: 'gingerbread'. See Collection >> #associationsDo: for another example. What do you think about it? :-) However, these are only my 2 cents without a clear opinion. Looking forward to your arguments! :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Freitag, 26. März 2021 19:08 Uhr An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz   Hi all! What do you think? Does it makes sense to pursue this idea of "dictionaries with collections as values" and enrich it with tests and documentation? Best, Marcel Am 26.03.2021 19:05:09 schrieb commits at source.squeak.org : A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-mt.932.mcz ==================== Summary ==================== Name: Collections-mt.932 Author: mt Time: 26 March 2021, 7:04:57.368373 pm UUID: b6c0c2c9-0a4f-684c-87a7-069813edd154 Ancestors: Collections-dtl.931 Sketch of a dictionary that has collections as values. dict := CollectionsDictionary new. (dict at: #fruits) addAll: #(apple apple peach). (dict at: #sweets) add: #nougat. dict removeKey: #sweets. dict explore. =============== Diff against Collections-dtl.931 =============== Item was added: + Dictionary subclass: #CollectionsDictionary + instanceVariableNames: 'collectionClass' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Unordered'! Item was added: + ----- Method: CollectionsDictionary class>>defaultCollectionClass (in category 'defaults') ----- + defaultCollectionClass + + ^ OrderedCollection! Item was added: + ----- Method: CollectionsDictionary class>>newOnBags (in category 'instance creation') ----- + newOnBags + + ^ self new + setCollectionClass: Bag; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnOrderedCollections (in category 'instance creation') ----- + newOnOrderedCollections + + ^ self new + setCollectionClass: OrderedCollection; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnSets (in category 'instance creation') ----- + newOnSets + + ^ self new + setCollectionClass: Set; + yourself! Item was added: + ----- Method: CollectionsDictionary>>at: (in category 'accessing') ----- + at: key + + ^ self at: key ifAbsent: [super at: key put: collectionClass new]! Item was added: + ----- Method: CollectionsDictionary>>at:put: (in category 'accessing') ----- + at: key put: value + + self shouldNotImplement.! Item was added: + ----- Method: CollectionsDictionary>>collectionClass (in category 'accessing') ----- + collectionClass + + ^ collectionClass! Item was added: + ----- Method: CollectionsDictionary>>initialize: (in category 'initialization') ----- + initialize: n + + super initialize: n. + self setCollectionClass: self class defaultCollectionClass.! Item was added: + ----- Method: CollectionsDictionary>>setCollectionClass: (in category 'initialization') ----- + setCollectionClass: aClass + + collectionClass := aClass.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Fri Mar 26 19:10:30 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Fri, 26 Mar 2021 19:10:30 +0000 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: References: <,> , Message-ID: <0dbb5e07cdf547b88bfcb61a9b1c4981@student.hpi.uni-potsdam.de> Hi Marcel, Hi Tony, > This proposal is just about avoiding the following: > > (myDict at: #fruits ifAbsentPut: [OrderedCollection new]) add: #apple. Well, but wouldn't a selector like I proposed (#makeListAt:) suffice to solve this problem? This would seem like a more lightweight approach to me than another subclass. :-) Regarding Tony's second invariant, maybe something like #cleanUpEmptyLists would suffice? Or #makeListAt:do: which automatically deletes the list if empty after evaluating aBlock ... > I think that some of your comments address problems with Dictionary or the collection hierarchy in general. Indeed, but my criticism was also about the number of subclasses in Collections in general. :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Freitag, 26. März 2021 20:03:24 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz Hi Christoph, thanks for the comments. I think that some of your comments address problems with Dictionary or the collection hierarchy in general. This proposal is just about avoiding the following: (myDict at: #fruits ifAbsentPut: [OrderedCollection new]) add: #apple. Best, Marcel Am 26.03.2021 19:50:40 schrieb Thiede, Christoph : Hi Marcel, I'm a bit afraid of creating more subclasses of Collection or Dictionary for two reasons: 1. Different subclasses are incompatible. If you wanted a special dictionary that has weak keys and holds collections, you would need to create another subclass and duplicate some of the logic. 2. Such a design change could introduce ambivalence and doubts about what subclass to choose, and if you choose the wrong class, you will need to do additional conversions. For example, should Collection >> #groupBy: return CollectionsDictionary instances with your proposal? If there is any other legacy code that does not use CollectionsDictionary, you will need to check or fix its type to avoid DNUs when further logic might be added to CollectionsDictionary later. Sometimes I have the feeling that the approach of creating too many collection/dictionary subclasses could violate the idea of polymorphy because they effectively remove genericity from their subclasses and refuse a lot of bequest (e.g., the math functions protocol from Collection). That being said, I'm not completely against the idea, but these are some common concerns I have on collection subclassing in general. I would like to avoid ending up with a convoluted design such as .NET has, which contains next to the generic List: StringList, StringCollection, StringDictionary, ListCollection, IntCollection, etc. ... :-) Hypothetically, an alternative approach would be to add a new protocol to an existing superclass, for example 'list enumerating' on Dictionary, which would provide for compatibility with other data structures. For example, existing items could even be wrapped into a list when doing something like: myDict at: #fruits put: #apple. (myDict makeListAt: #fruits) addAll: #(banana cherry date). (myDict makeListAt: #sweets) add: 'eclair; add: 'froyo'; add: 'gingerbread'. See Collection >> #associationsDo: for another example. What do you think about it? :-) However, these are only my 2 cents without a clear opinion. Looking forward to your arguments! :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Freitag, 26. März 2021 19:08 Uhr An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz Hi all! What do you think? Does it makes sense to pursue this idea of "dictionaries with collections as values" and enrich it with tests and documentation? Best, Marcel Am 26.03.2021 19:05:09 schrieb commits at source.squeak.org : A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-mt.932.mcz ==================== Summary ==================== Name: Collections-mt.932 Author: mt Time: 26 March 2021, 7:04:57.368373 pm UUID: b6c0c2c9-0a4f-684c-87a7-069813edd154 Ancestors: Collections-dtl.931 Sketch of a dictionary that has collections as values. dict := CollectionsDictionary new. (dict at: #fruits) addAll: #(apple apple peach). (dict at: #sweets) add: #nougat. dict removeKey: #sweets. dict explore. =============== Diff against Collections-dtl.931 =============== Item was added: + Dictionary subclass: #CollectionsDictionary + instanceVariableNames: 'collectionClass' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Unordered'! Item was added: + ----- Method: CollectionsDictionary class>>defaultCollectionClass (in category 'defaults') ----- + defaultCollectionClass + + ^ OrderedCollection! Item was added: + ----- Method: CollectionsDictionary class>>newOnBags (in category 'instance creation') ----- + newOnBags + + ^ self new + setCollectionClass: Bag; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnOrderedCollections (in category 'instance creation') ----- + newOnOrderedCollections + + ^ self new + setCollectionClass: OrderedCollection; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnSets (in category 'instance creation') ----- + newOnSets + + ^ self new + setCollectionClass: Set; + yourself! Item was added: + ----- Method: CollectionsDictionary>>at: (in category 'accessing') ----- + at: key + + ^ self at: key ifAbsent: [super at: key put: collectionClass new]! Item was added: + ----- Method: CollectionsDictionary>>at:put: (in category 'accessing') ----- + at: key put: value + + self shouldNotImplement.! Item was added: + ----- Method: CollectionsDictionary>>collectionClass (in category 'accessing') ----- + collectionClass + + ^ collectionClass! Item was added: + ----- Method: CollectionsDictionary>>initialize: (in category 'initialization') ----- + initialize: n + + super initialize: n. + self setCollectionClass: self class defaultCollectionClass.! Item was added: + ----- Method: CollectionsDictionary>>setCollectionClass: (in category 'initialization') ----- + setCollectionClass: aClass + + collectionClass := aClass.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From marcel.taeumel at hpi.de Fri Mar 26 19:17:42 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Fri, 26 Mar 2021 20:17:42 +0100 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: <0dbb5e07cdf547b88bfcb61a9b1c4981@student.hpi.uni-potsdam.de> References: <,> <,> <0dbb5e07cdf547b88bfcb61a9b1c4981@student.hpi.uni-potsdam.de> Message-ID: Hi Christoph. > Well, but wouldn't a selector like I proposed (#makeListAt:) suffice to solve this problem? > This would seem like a more lightweight approach to me than another subclass. :-) I suppose not. It would be more difficult to use because you expect the clients to use another interface. The kind of dictionary object can easily be hidden. Best, Marcel Am 26.03.2021 20:10:41 schrieb Thiede, Christoph : Hi Marcel, Hi Tony, > This proposal is just about avoiding the following: >  > (myDict at: #fruits ifAbsentPut: [OrderedCollection new]) add: #apple. Well, but wouldn't a selector like I proposed (#makeListAt:) suffice to solve this problem? This would seem like a more lightweight approach to me than another subclass. :-) Regarding Tony's second invariant, maybe something like #cleanUpEmptyLists would suffice? Or #makeListAt:do: which automatically deletes the list if empty after evaluating aBlock ... > I think that some of your comments address problems with Dictionary or the collection hierarchy in general. Indeed, but my criticism was also about the number of subclasses in Collections in general. :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Freitag, 26. März 2021 20:03:24 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz   Hi Christoph, thanks for the comments. I think that some of your comments address problems with Dictionary or the collection hierarchy in general.  This proposal is just about avoiding the following: (myDict at: #fruits ifAbsentPut: [OrderedCollection new]) add: #apple. Best, Marcel Am 26.03.2021 19:50:40 schrieb Thiede, Christoph : Hi Marcel, I'm a bit afraid of creating more subclasses of Collection or Dictionary for two reasons: 1. Different subclasses are incompatible. If you wanted a special dictionary that has weak keys and holds collections, you would need to create another subclass and duplicate some of the logic. 2. Such a design change could introduce ambivalence and doubts about what subclass to choose, and if you choose the wrong class, you will need to do additional conversions. For example, should Collection >> #groupBy: return CollectionsDictionary instances with your proposal? If there is any other legacy code that does not use CollectionsDictionary, you will need to check or fix its type to avoid DNUs when further logic might be added to CollectionsDictionary later. Sometimes I have the feeling that the approach of creating too many collection/dictionary subclasses could violate the idea of polymorphy because they effectively remove genericity from their subclasses and refuse a lot of bequest (e.g., the math functions protocol from Collection). That being said, I'm not completely against the idea, but these are some common concerns I have on collection subclassing in general. I would like to avoid ending up with a convoluted design such as .NET has, which contains next to the generic List: StringList, StringCollection, StringDictionary, ListCollection, IntCollection, etc. ... :-) Hypothetically, an alternative approach would be to add a new protocol to an existing superclass, for example 'list enumerating' on Dictionary, which would provide for compatibility with other data structures. For example, existing items could even be wrapped into a list when doing something like: myDict at: #fruits put: #apple. (myDict makeListAt: #fruits) addAll: #(banana cherry date). (myDict makeListAt: #sweets) add: 'eclair; add: 'froyo'; add: 'gingerbread'. See Collection >> #associationsDo: for another example. What do you think about it? :-) However, these are only my 2 cents without a clear opinion. Looking forward to your arguments! :-) Best, Christoph Von: Squeak-dev im Auftrag von Taeumel, Marcel Gesendet: Freitag, 26. März 2021 19:08 Uhr An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz   Hi all! What do you think? Does it makes sense to pursue this idea of "dictionaries with collections as values" and enrich it with tests and documentation? Best, Marcel Am 26.03.2021 19:05:09 schrieb commits at source.squeak.org : A new version of Collections was added to project The Inbox: http://source.squeak.org/inbox/Collections-mt.932.mcz ==================== Summary ==================== Name: Collections-mt.932 Author: mt Time: 26 March 2021, 7:04:57.368373 pm UUID: b6c0c2c9-0a4f-684c-87a7-069813edd154 Ancestors: Collections-dtl.931 Sketch of a dictionary that has collections as values. dict := CollectionsDictionary new. (dict at: #fruits) addAll: #(apple apple peach). (dict at: #sweets) add: #nougat. dict removeKey: #sweets. dict explore. =============== Diff against Collections-dtl.931 =============== Item was added: + Dictionary subclass: #CollectionsDictionary + instanceVariableNames: 'collectionClass' + classVariableNames: '' + poolDictionaries: '' + category: 'Collections-Unordered'! Item was added: + ----- Method: CollectionsDictionary class>>defaultCollectionClass (in category 'defaults') ----- + defaultCollectionClass + + ^ OrderedCollection! Item was added: + ----- Method: CollectionsDictionary class>>newOnBags (in category 'instance creation') ----- + newOnBags + + ^ self new + setCollectionClass: Bag; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnOrderedCollections (in category 'instance creation') ----- + newOnOrderedCollections + + ^ self new + setCollectionClass: OrderedCollection; + yourself! Item was added: + ----- Method: CollectionsDictionary class>>newOnSets (in category 'instance creation') ----- + newOnSets + + ^ self new + setCollectionClass: Set; + yourself! Item was added: + ----- Method: CollectionsDictionary>>at: (in category 'accessing') ----- + at: key + + ^ self at: key ifAbsent: [super at: key put: collectionClass new]! Item was added: + ----- Method: CollectionsDictionary>>at:put: (in category 'accessing') ----- + at: key put: value + + self shouldNotImplement.! Item was added: + ----- Method: CollectionsDictionary>>collectionClass (in category 'accessing') ----- + collectionClass + + ^ collectionClass! Item was added: + ----- Method: CollectionsDictionary>>initialize: (in category 'initialization') ----- + initialize: n + + super initialize: n. + self setCollectionClass: self class defaultCollectionClass.! Item was added: + ----- Method: CollectionsDictionary>>setCollectionClass: (in category 'initialization') ----- + setCollectionClass: aClass + + collectionClass := aClass.! -------------- next part -------------- An HTML attachment was scrubbed... URL: From tonyg at leastfixedpoint.com Fri Mar 26 19:26:31 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Fri, 26 Mar 2021 20:26:31 +0100 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: References: <,> <,> <0dbb5e07cdf547b88bfcb61a9b1c4981@student.hpi.uni-potsdam.de> Message-ID: <7c499f8a-8f58-7cd9-36b8-42916cdd50e2@leastfixedpoint.com> What about something like: collection: aClass at: key do: aBlock | coll result | coll := self at: key ifAbsentPut: [aClass new]. result := aBlock value: coll. coll ifEmpty: [self removeKey: key]. ^ result ... perhaps with `ensure:` to do the removal? Then: myDictOfSets collection: Set at: #key1 do: [:s | s add: 123]. On 3/26/21 8:17 PM, Marcel Taeumel wrote: > ... From Christoph.Thiede at student.hpi.uni-potsdam.de Sat Mar 27 18:35:56 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sat, 27 Mar 2021 18:35:56 +0000 Subject: [squeak-dev] Possible code smell? - Abstract Collection members not overridden Message-ID: Hi all, just a quick thought while working with some collections: There are a number of non-abstract Collection subclasses that do not override abstract members of Collection, such as #add: or #remove:ifAbsent:: Collection allSubclasses select: [:class | (class lookupSelector: #add:) = (Collection >> #add:)]. Collection allSubclasses select: [:class | (class lookupSelector: #remove:ifAbsent:) = (Collection >> #remove:ifAbsent:)]. I.e. for example, RunArray new add: 1 raises a SubclassResponsibility rather than a NotImplemented (#shouldNotImplement) exception. Do you think this is a code smell/erroneous behavior and should be fixed? Or should we just use #shouldNotImplement in Collection >> #add: & Co.? We might have similar effects in other hierarchies, but I did not check my entire image for them ... Best, Christoph -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Sat Mar 27 18:47:52 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sat, 27 Mar 2021 18:47:52 +0000 Subject: [squeak-dev] #identityCaseOf: Message-ID: Hi all, the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate nested if blocks (for one of many examples, take a look at PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], however, I confused equality and identity (I have to admit that this is a common error of mines) so I had to convert my beautiful #caseOf: statement back to a boring list of if checks. I wonder whether we could - or should - introduce something like #identityCaseOf:otherwise: (names subjected to discussion) for such situations? Historically, I guess this has not been built because #caseOf: has probably been inspired by the switch/select/case statement of other languages, which usually only accept constant case values. But in Smalltalk, luckily, we do not have this restriction, thus I'm wondering whether there is any reason to have #caseOf: but not #identityCaseOf:. Looking forward to your opinions! :-) Best, Christoph [1] https://github.com/LinqLover/SimulationStudio/commit/ddf0ef3e21c63a2fd9b08703c8e9ff213b7b6b0b -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Sat Mar 27 19:00:30 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sat, 27 Mar 2021 19:00:30 +0000 Subject: [squeak-dev] The Inbox: Collections-mt.932.mcz In-Reply-To: <7c499f8a-8f58-7cd9-36b8-42916cdd50e2@leastfixedpoint.com> References: <,> <,> <0dbb5e07cdf547b88bfcb61a9b1c4981@student.hpi.uni-potsdam.de> , <7c499f8a-8f58-7cd9-36b8-42916cdd50e2@leastfixedpoint.com> Message-ID: Hi Marcel, do I understand correctly that your point is to reach polymorphy with other types of dictionaries? Well, that changes things, of course. :-) (Then again, which client can expect a regular dictionary not to answer KeyNotFound for arbitrary items that have not been added before? ) I think the use case of mapping values to collections is not being represented in a sufficient way in the current Collections API, thus I find your proposal very interesting. For reference, .NET has IGrouping`2 which appears as a similar concept to me. I don't want to block your proposal in any way (not that I would be in that position at all :D), I'm just curious about our plans on subclassing Dictionary in general. Just for interest, do you maybe have some other concrete use cases for a CollectionsDictionary in Squeak? :-) Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Tony Garnock-Jones Gesendet: Freitag, 26. März 2021 20:26:31 An: The general-purpose Squeak developers list; Taeumel, Marcel Betreff: Re: [squeak-dev] The Inbox: Collections-mt.932.mcz What about something like: collection: aClass at: key do: aBlock | coll result | coll := self at: key ifAbsentPut: [aClass new]. result := aBlock value: coll. coll ifEmpty: [self removeKey: key]. ^ result ... perhaps with `ensure:` to do the removal? Then: myDictOfSets collection: Set at: #key1 do: [:s | s add: 123]. On 3/26/21 8:17 PM, Marcel Taeumel wrote: > ... -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Sat Mar 27 23:46:48 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sat, 27 Mar 2021 19:46:48 -0400 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: Message-ID: <20210327234648.GA60256@shell.msen.com> On Sat, Mar 27, 2021 at 06:47:52PM +0000, Thiede, Christoph wrote: > Hi all, > > > the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? > IMHO, this is not needed. It seems like cognitive clutter to me. > > Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate nested if blocks (for one of many examples, take a look at PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], however, I confused equality and identity (I have to admit that this is a common error of mines) so I had to convert my beautiful #caseOf: statement back to a boring list of if checks. I wonder whether we could - or should - introduce something like #identityCaseOf:otherwise: (names subjected to discussion) for such situations? > Looking at your example, I find the boring list of if checks to be easier to read and understand. If you were to implement it with #identityCaseOf:[otherwise:] then I, as the reader of the code, would need to understand the distinction between #caseOf: and #identityCaseOf:. That is not difficult, but it would be an unnecessary distraction compared to your boring code, which I find to be already very clear. Furthermore, your boring implementation is more concise, and it does not require an extra clause for the otherwise: case. > > Historically, I guess this has not been built because #caseOf: has probably been inspired by the switch/select/case statement of other languages, which usually only accept constant case values. But in Smalltalk, luckily, we do not have this restriction, thus I'm wondering whether there is any reason to have #caseOf: but not #identityCaseOf:. Looking forward to your opinions! :-) > If you were to add #identityCaseOf:[otherwise:] to the protocol of Object, there is a risk that people would perceive it as a feature of the language, and as something that they should try to incorporate into their own code. That would not be a good thing. Interesting idea though :-) Dave From tim at rowledge.org Sun Mar 28 05:12:19 2021 From: tim at rowledge.org (tim Rowledge) Date: Sat, 27 Mar 2021 22:12:19 -0700 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: Message-ID: > On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: > > Hi all, > > the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim The gains I make don't make me a hero; all the work I do is just to get back to Zero From leves at caesar.elte.hu Sun Mar 28 08:33:32 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Sun, 28 Mar 2021 10:33:32 +0200 (CEST) Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: Message-ID: Hi Christoph, I see some value having #identityCaseOf:, so +1 from me. But what would be a more interesting thing to explore (yes, I'm derailing this conversation now because the answer to your question is yes already :)) is to extend the functionality of #caseOf:. For example, passing the object to the condition block (or even the result block) could be useful: self someComplexExpression caseOf: { [ 1 ] -> [ self success ] [ :value | value odd ] -> [ :value | self processEvenValue: value - 1 ]. [ :value | true "it's even ] -> [ :value | self processEvenValue ] } There are two new things in the example: - the value of self someComplexExpression is optionally passed to the blocks. Yes, that could be done by creating a temporary variable. The compiler could do exactly that behind the scenes. - when the value is passed to the matcher block, possibilities are greatly extended. For example, it could even reproduce #identityCaseOf: foo caseOf: { [ :o | o == #foo ] -> [ self foo ]. [ :o | o == #bar ] -> [ self bar ] } The same thing could be done with the otherwise block too: self foo caseOf: { ... } otherwise: [ :value | value ] Levente On Sat, 27 Mar 2021, Thiede, Christoph wrote: > > Hi all, > > > the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? > > > Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate nested if blocks (for one of many examples, take a look at PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], however, I confused > equality and identity (I have to admit that this is a common error of mines) so I had to convert my beautiful #caseOf: statement back to a boring list of if checks. I wonder whether we could - or should - introduce something > like #identityCaseOf:otherwise: (names subjected to discussion) for such situations? > > > Historically, I guess this has not been built because #caseOf: has probably been inspired by the switch/select/case statement of other languages, which usually only accept constant case values. But in Smalltalk, luckily, we > do not have this restriction, thus I'm wondering whether there is any reason to have #caseOf: but not #identityCaseOf:. Looking forward to your opinions! :-) > > > Best, > > Christoph > > > [1] https://github.com/LinqLover/SimulationStudio/commit/ddf0ef3e21c63a2fd9b08703c8e9ff213b7b6b0b > > From m at jaromir.net Sun Mar 28 08:34:57 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 28 Mar 2021 03:34:57 -0500 (CDT) Subject: [squeak-dev] Bug in Process>>#terminate | Returning from unwind contexts In-Reply-To: <1616660158843-0.post@n4.nabble.com> References: <1615283642086-0.post@n4.nabble.com> <3241f8cf091b41bbb5d215447cb8b287@student.hpi.uni-potsdam.de> <1615797306053-0.post@n4.nabble.com> <1615841680085-0.post@n4.nabble.com> <1615901797162-0.post@n4.nabble.com> <1616011686241-0.post@n4.nabble.com> <1616586593553-0.post@n4.nabble.com> <1616660158843-0.post@n4.nabble.com> Message-ID: <1616920497663-0.post@n4.nabble.com> Hi Christoph, All, I'm enclosing a changeset that could solve the original issue: unwind errors and image instability after Abandoning the debugger in Christoph's example: [self error] ensure: [^2] The unwind errors also appears in common situations like: [self error] ensure: [self error] The root cause of the problem is that termination of a suspended process is performed indirectly via #evaluate:onBehalf: in #popTo (as if in simulation). Christoph described the problem above and elsewhere. The solution may be to replace the #popTo: mechanism by having the suspended process terminate itself as an active process by placing a new context atop its stack to invoke #terminate, and resume the suspended process with the active process' priority. This, however leaves us with another problem: when a non-local return is executed in an unwind block during termination the process may jump over it's termination back to the original do-it code and continue executing - which is in my opinion precisely the semantics of the non-local return in this case (see #valueUninterruptably). But the problem is the original UI process that started the do-it continues and the new UI process that opened a debugger continues as well, alternating control. To avoid this twin UI situation we have to make sure the original UI is terminated after finishing execution of the do-it code that escaped its termination via a non-local return. To do this we may insert a context invoking #teminate under the DoIt context in the stack when we hit Abandon and the debugger tries to terminate the debugged do-it code. We cannot modify the stack sooner because we may hit Proceed and let the process continue (which would close the new debugger process and leave the original process as the sole UI process). The change involves two methods only: Debugger>>windowIsClosing a Process>>terminate. Please review the enclosed changeset with my comments; I'd appreciate any feedback. Thanks! NonLocalReturnTermination.cs ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From rebmekop at gmail.com Sun Mar 28 10:39:34 2021 From: rebmekop at gmail.com (=?UTF-8?B?QmFsw6F6cyBLw7NzaQ==?=) Date: Sun, 28 Mar 2021 12:39:34 +0200 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: Message-ID: Hi Christoph, Just a side note concerning the code you linked: Is checking error for nil in line 15 necessary? Balázs On Sat, Mar 27, 2021 at 7:47 PM Thiede, Christoph < Christoph.Thiede at student.hpi.uni-potsdam.de> wrote: > Hi all, > > > the proposal is in the title. :-) Do you think we could need something > like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], > on Object? > > > Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate > nested if blocks (for one of many examples, take a look at > PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], > however, I confused equality and identity (I have to admit that this is a > common error of mines) so I had to convert my beautiful #caseOf: > statement back to a boring list of if checks. I wonder whether we could - > or should - introduce something like #identityCaseOf:otherwise: (names > subjected to discussion) for such situations? > > > Historically, I guess this has not been built because #caseOf: has > probably been inspired by the switch/select/case statement of other > languages, which usually only accept constant case values. But in > Smalltalk, luckily, we do not have this restriction, thus I'm wondering > whether there is any reason to have #caseOf: but not #identityCaseOf:. > Looking forward to your opinions! :-) > > > Best, > > Christoph > > > [1] > https://github.com/LinqLover/SimulationStudio/commit/ddf0ef3e21c63a2fd9b08703c8e9ff213b7b6b0b > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Sun Mar 28 11:09:48 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sun, 28 Mar 2021 11:09:48 +0000 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: , Message-ID: <9d7b625fce5847c187d77d373430ceb9@student.hpi.uni-potsdam.de> Hi all, thanks for all the opinions! :-) I see that the general use of #caseOf:[otherwise:] is probably of matter of taste - personally, I like it to remove duplication. Kent Beck even recommends refactoring something like this: aBoolean ifTrue: [^1] ifFalse: [^2] to something like that: ^ aBoolean ifTrue: [1] ifFalse: [2] So I have the feeling that he would also recommend refactoring anInteger = 1 ifTrue: [^ #one]. anInteger = 2 ifTrue: [^ #two]. anInteger = 3 ifTrue: [^ #three]. ^ self error to: anInteger caseOf: { [1] -> [#one]. [2] -> [#two]. [3] -> [#three] } However, I don't know him personally, so this is an assumption only, of course. ;-) @David: I find your thoughts about boring code interesting. My personal perspective is rather different, I always try to minimize duplication, but I have already been having many discussions about this with some fellow students, so probably, the best solution lies somewhere in the middle between boringness (Robert Martin) and deduplication (Kent Beck) ... :-) > If you were to add #identityCaseOf:[otherwise:] to the protocol of Object, there is a risk that people would perceive it as a feature of the language, and as something that they should try to incorporate into their own code. That would not be a good thing. Why not (except the reasons you listed above), if I may ask? :-) #caseOf:[otherwise:] already *is* part of the protocol of Object, and so are #yourself and #in:, too. IMHO they are kind of features of the language - not a syntactical way, thanks to Smalltalk minimalism, but still, they are understood by every object. Unless we deprecate them, we should indeed assume that people use them, of course. @Tim: > Far too like C. Again, why please? :-) I'm not a big fan of C either, but IMO switch/select/case is not the worst concept when it allows you to eliminate some duplication. Still, I would not say #caseOf:[otherwise:] is the end goal in every case - often it helps you to identify data in your code, and a further refactoring step could be to extract the data into a separate method as a dictionary. See [1] for further thoughts about this. @Levente: Glad you like it! Regarding arguments, did you read [2]? It's already a bit older but I have not continued working on this since I'm afraid have not got any feedback on the proposal. :-) [1] https://twitter.com/LinqLover/status/1375191096658178050 [2] http://forum.world.st/Merge-Request-caseOf-otherwise-with-arguments-td5112223.html Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Levente Uzonyi Gesendet: Sonntag, 28. März 2021 10:33:32 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] #identityCaseOf: Hi Christoph, I see some value having #identityCaseOf:, so +1 from me. But what would be a more interesting thing to explore (yes, I'm derailing this conversation now because the answer to your question is yes already :)) is to extend the functionality of #caseOf:. For example, passing the object to the condition block (or even the result block) could be useful: self someComplexExpression caseOf: { [ 1 ] -> [ self success ] [ :value | value odd ] -> [ :value | self processEvenValue: value - 1 ]. [ :value | true "it's even ] -> [ :value | self processEvenValue ] } There are two new things in the example: - the value of self someComplexExpression is optionally passed to the blocks. Yes, that could be done by creating a temporary variable. The compiler could do exactly that behind the scenes. - when the value is passed to the matcher block, possibilities are greatly extended. For example, it could even reproduce #identityCaseOf: foo caseOf: { [ :o | o == #foo ] -> [ self foo ]. [ :o | o == #bar ] -> [ self bar ] } The same thing could be done with the otherwise block too: self foo caseOf: { ... } otherwise: [ :value | value ] Levente On Sat, 27 Mar 2021, Thiede, Christoph wrote: > > Hi all, > > > the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? > > > Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate nested if blocks (for one of many examples, take a look at PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], however, I confused > equality and identity (I have to admit that this is a common error of mines) so I had to convert my beautiful #caseOf: statement back to a boring list of if checks. I wonder whether we could - or should - introduce something > like #identityCaseOf:otherwise: (names subjected to discussion) for such situations? > > > Historically, I guess this has not been built because #caseOf: has probably been inspired by the switch/select/case statement of other languages, which usually only accept constant case values. But in Smalltalk, luckily, we > do not have this restriction, thus I'm wondering whether there is any reason to have #caseOf: but not #identityCaseOf:. Looking forward to your opinions! :-) > > > Best, > > Christoph > > > [1] https://github.com/LinqLover/SimulationStudio/commit/ddf0ef3e21c63a2fd9b08703c8e9ff213b7b6b0b > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From Das.Linux at gmx.de Sun Mar 28 11:39:53 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Sun, 28 Mar 2021 13:39:53 +0200 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: Message-ID: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> Hi > On 28. Mar 2021, at 07:12, tim Rowledge wrote: > > > >> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >> >> Hi all, >> >> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? > > I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." > Exactly. If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. (as in the case of #update: update: aSymbol aSymbol == #foo ifTrue: [^ self knorz]. aSymbol == #bar ifTrue: [^ self berfp]. ^ false I think this is sufficient. Otherwise, use an IdentityDictionary? Best regards -Tobias From Christoph.Thiede at student.hpi.uni-potsdam.de Sun Mar 28 11:47:52 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sun, 28 Mar 2021 11:47:52 +0000 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: , Message-ID: <9472c16b1fdd4dc0b2d6c09cdf698938@student.hpi.uni-potsdam.de> Hi Balázs, absolutely right. Thanks for your hint, I just committed the change to SimulationStudio. [1] Best, Christoph [1] https://github.com/LinqLover/SimulationStudio/pull/23 ________________________________ Von: Squeak-dev im Auftrag von Balázs Kósi Gesendet: Sonntag, 28. März 2021 12:39:34 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] #identityCaseOf: Hi Christoph, Just a side note concerning the code you linked: Is checking error for nil in line 15 necessary? Balázs On Sat, Mar 27, 2021 at 7:47 PM Thiede, Christoph > wrote: Hi all, the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate nested if blocks (for one of many examples, take a look at PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], however, I confused equality and identity (I have to admit that this is a common error of mines) so I had to convert my beautiful #caseOf: statement back to a boring list of if checks. I wonder whether we could - or should - introduce something like #identityCaseOf:otherwise: (names subjected to discussion) for such situations? Historically, I guess this has not been built because #caseOf: has probably been inspired by the switch/select/case statement of other languages, which usually only accept constant case values. But in Smalltalk, luckily, we do not have this restriction, thus I'm wondering whether there is any reason to have #caseOf: but not #identityCaseOf:. Looking forward to your opinions! :-) Best, Christoph [1] https://github.com/LinqLover/SimulationStudio/commit/ddf0ef3e21c63a2fd9b08703c8e9ff213b7b6b0b -------------- next part -------------- An HTML attachment was scrubbed... URL: From christoph.thiede at student.hpi.uni-potsdam.de Sun Mar 28 11:51:24 2021 From: christoph.thiede at student.hpi.uni-potsdam.de (Christoph Thiede) Date: Sun, 28 Mar 2021 06:51:24 -0500 (CDT) Subject: [squeak-dev] Problems with #caseError In-Reply-To: <62981f221bd34220ba22fda263080cd0@student.hpi.uni-potsdam.de> References: <69dd1997c7844439bda1b7b15e40cc01@student.hpi.uni-potsdam.de> <7cb95adc46fc4e1294f93babc605f2c2@student.hpi.uni-potsdam.de> <32f9227ca5a2496485461b9a644cccc6@student.hpi.uni-potsdam.de> <91153db2ef7845cc875bc038dcb7dca2@student.hpi.uni-potsdam.de> <62981f221bd34220ba22fda263080cd0@student.hpi.uni-potsdam.de> Message-ID: <1616932284132-0.post@n4.nabble.com> Hi all, this is a small reminder, this changeset is still pending review. Would it be possible to get this merged before the next release? :-) Best, Christoph ----- Carpe Squeak! -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From lewis at mail.msen.com Sun Mar 28 14:02:31 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sun, 28 Mar 2021 10:02:31 -0400 Subject: [squeak-dev] Problems with #caseError In-Reply-To: <1616932284132-0.post@n4.nabble.com> References: <69dd1997c7844439bda1b7b15e40cc01@student.hpi.uni-potsdam.de> <7cb95adc46fc4e1294f93babc605f2c2@student.hpi.uni-potsdam.de> <32f9227ca5a2496485461b9a644cccc6@student.hpi.uni-potsdam.de> <91153db2ef7845cc875bc038dcb7dca2@student.hpi.uni-potsdam.de> <62981f221bd34220ba22fda263080cd0@student.hpi.uni-potsdam.de> <1616932284132-0.post@n4.nabble.com> Message-ID: <20210328140231.GA46725@shell.msen.com> Hi Christoph, On Sun, Mar 28, 2021 at 06:51:24AM -0500, Christoph Thiede wrote: > Hi all, > > this is a small reminder, this changeset is still pending review. Would it > be possible to get this merged before the next release? :-) > Perhaps you can update the changes and maybe submit back to the inbox? Looking at the change set, I see that your change to Object is already in the image, and there have been more recent changes to MessageNode that presumably would require merging. I expect that the remaining change would be a small update to the Compiler package. I should note that it took me quite some time to figure out the context of this message. I think it is because of this: > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > Apparently you send this as a reply from the forum, but the resulting email here on the list provided no context for the thread you were discussing. I was unable to find any prior emails with this subject in the recent archives. I finally figured it out when I noticed the "Sent from:" line at the bottom of your message. Dave From leves at caesar.elte.hu Sun Mar 28 14:03:51 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Sun, 28 Mar 2021 16:03:51 +0200 (CEST) Subject: [squeak-dev] #identityCaseOf: In-Reply-To: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> References: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> Message-ID: On Sun, 28 Mar 2021, Tobias Pape wrote: > Hi > > >> On 28. Mar 2021, at 07:12, tim Rowledge wrote: >> >> >> >>> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >>> >>> Hi all, >>> >>> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? >> >> I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." >> > > Exactly. > If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. > (as in the case of #update: > > update: aSymbol > > aSymbol == #foo ifTrue: [^ self knorz]. > aSymbol == #bar ifTrue: [^ self berfp]. > ^ false > > I think this is sufficient. Those ifTrue:'s quickly render your code unreadable or force you to extract chunks of your code into a separate method which can impair legibility. > > Otherwise, use an IdentityDictionary? Ah, the good old Pharo-way of doing things. :D All-in-all, it looks as though we're slipping into another caseOf: vs no-caseOf: discussion. Let's not do that. Levente > > Best regards > -Tobias From leves at caesar.elte.hu Sun Mar 28 14:08:49 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Sun, 28 Mar 2021 16:08:49 +0200 (CEST) Subject: [squeak-dev] #identityCaseOf: In-Reply-To: <9d7b625fce5847c187d77d373430ceb9@student.hpi.uni-potsdam.de> References: , <9d7b625fce5847c187d77d373430ceb9@student.hpi.uni-potsdam.de> Message-ID: On Sun, 28 Mar 2021, Thiede, Christoph wrote: > > Hi all, > > > thanks for all the opinions! :-)  > > > I see that the general use of #caseOf:[otherwise:] is probably of matter of taste - personally, I like it to remove duplication. Kent Beck even recommends refactoring something like this: > aBoolean ifTrue: [^1] ifFalse: [^2] > > to something like that: > ^ aBoolean ifTrue: [1] ifFalse: [2] > > So I have the feeling that he would also recommend refactoring > anInteger = 1 ifTrue: [^ #one]. > anInteger = 2 ifTrue: [^ #two]. > anInteger = 3 ifTrue: [^ #three]. > ^ self error > > to: > anInteger caseOf: { >     [1] -> [#one]. >     [2] -> [#two]. >     [3] -> [#three] } > > However, I don't know him personally, so this is an assumption only, of course. ;-) > > @David: I find your thoughts about boring code interesting. My personal perspective is rather different, I always try to minimize duplication, but I have already been having many discussions about this with some fellow > students, so probably, the best solution lies somewhere in the middle between boringness (Robert Martin) and deduplication (Kent Beck) ... :-) > > > If you were to add #identityCaseOf:[otherwise:] to the protocol of Object, there is a risk that people would perceive it as a feature of the language, and as something that they should try to incorporate into their own > code. That would not be a good thing. > Why not (except the reasons you listed above), if I may ask? :-) #caseOf:[otherwise:] already *is* part of the protocol of Object, and so are #yourself and #in:, too. IMHO they are kind of features of the language - not a > syntactical way, thanks to Smalltalk minimalism, but still, they are understood by every object. Unless we deprecate them, we should indeed assume that people use them, of course. > > @Tim: > > > Far too like C. > > Again, why please? :-) I'm not a big fan of C either, but IMO switch/select/case is not the worst concept when it allows you to eliminate some duplication. Still, I would not say #caseOf:[otherwise:] is the end goal in every > case - often it helps you to identify data in your code, and a further refactoring step could be to extract the data into a separate method as a dictionary. See [1] for further thoughts about this. > > @Levente: Glad you like it! Regarding arguments, did you read [2]? It's already a bit older but I have not continued working on this since I'm afraid have not got any feedback on the proposal. :-) I had a look at the change set. It looks good but seems to lack decompiler-related changes which I think are necessary to keep the decompiler working. Levente > > [1] https://twitter.com/LinqLover/status/1375191096658178050 > [2] http://forum.world.st/Merge-Request-caseOf-otherwise-with-arguments-td5112223.html > > Best, > Christoph > > _________________________________________________________________________________________________________________________________________________________________________________________________________________________________ > Von: Squeak-dev im Auftrag von Levente Uzonyi > Gesendet: Sonntag, 28. März 2021 10:33:32 > An: The general-purpose Squeak developers list > Betreff: Re: [squeak-dev] #identityCaseOf:   > Hi Christoph, > > I see some value having #identityCaseOf:, so +1 from me. > > But what would be a more interesting thing to explore (yes, I'm derailing > this conversation now because the answer to your question is yes already > :)) is to extend the functionality of #caseOf:. > > For example, passing the object to the condition block (or even the result > block) could be useful: > > self someComplexExpression caseOf: { >          [ 1 ] -> [ self success ] >          [ :value | value odd ] -> [ :value | self processEvenValue: value - 1 ]. >          [ :value | true "it's even ] -> [ :value | self processEvenValue ] } > > There are two new things in the example: > - the value of self someComplexExpression is optionally passed to the > blocks. Yes, that could be done by creating a temporary variable. The > compiler could do exactly that behind the scenes. > - when the value is passed to the matcher block, possibilities are greatly > extended. For example, it could even reproduce #identityCaseOf: > >          foo caseOf: { >                  [ :o | o == #foo ] -> [ self foo ]. >                  [ :o | o == #bar ] -> [ self bar ] } > > The same thing could be done with the otherwise block too: > >          self foo >                  caseOf: { ... } >                  otherwise: [ :value | value ] > > > Levente > > > On Sat, 27 Mar 2021, Thiede, Christoph wrote: > > > > > Hi all, > > > > > > the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? > > > > > > Here is my motivation: I very often use #caseOf:[otherwise:] to eliminate nested if blocks (for one of many examples, take a look at PreferenceBrowserMorph >> #keyPressed:). In one recent situation [1], however, I confused > > equality and identity (I have to admit that this is a common error of mines) so I had to convert my beautiful #caseOf: statement back to a boring list of if checks. I wonder whether we could - or should - introduce > something > > like #identityCaseOf:otherwise: (names subjected to discussion) for such situations? > > > > > > Historically, I guess this has not been built because #caseOf: has probably been inspired by the switch/select/case statement of other languages, which usually only accept constant case values. But in Smalltalk, luckily, we > > do not have this restriction, thus I'm wondering whether there is any reason to have #caseOf: but not #identityCaseOf:. Looking forward to your opinions! :-) > > > > > > Best, > > > > Christoph > > > > > > [1] https://github.com/LinqLover/SimulationStudio/commit/ddf0ef3e21c63a2fd9b08703c8e9ff213b7b6b0b > > > > > > From Das.Linux at gmx.de Sun Mar 28 14:45:30 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Sun, 28 Mar 2021 16:45:30 +0200 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> Message-ID: > On 28. Mar 2021, at 16:03, Levente Uzonyi wrote: > > On Sun, 28 Mar 2021, Tobias Pape wrote: > >> Hi >> >> >>> On 28. Mar 2021, at 07:12, tim Rowledge wrote: >>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >>>> Hi all, >>>> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? >>> I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." >> >> Exactly. >> If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. >> (as in the case of #update: >> >> update: aSymbol >> >> aSymbol == #foo ifTrue: [^ self knorz]. >> aSymbol == #bar ifTrue: [^ self berfp]. >> ^ false >> >> I think this is sufficient. > > Those ifTrue:'s quickly render your code unreadable or force you to extract chunks of your code into a separate method which can impair legibility. > >> >> Otherwise, use an IdentityDictionary? > > Ah, the good old Pharo-way of doing things. :D what? -t > > All-in-all, it looks as though we're slipping into another caseOf: vs no-caseOf: discussion. Let's not do that. > > > Levente > >> >> Best regards >> -Tobias From Das.Linux at gmx.de Sun Mar 28 14:48:22 2021 From: Das.Linux at gmx.de (Tobias Pape) Date: Sun, 28 Mar 2021 16:48:22 +0200 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> Message-ID: <3E24C1AF-9FD7-41A9-A6E9-999C02E196BD@gmx.de> > On 28. Mar 2021, at 16:03, Levente Uzonyi wrote: > > On Sun, 28 Mar 2021, Tobias Pape wrote: > >> Hi >> >> >>> On 28. Mar 2021, at 07:12, tim Rowledge wrote: >>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >>>> Hi all, >>>> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? >>> I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." >> >> Exactly. >> If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. >> (as in the case of #update: >> >> update: aSymbol >> >> aSymbol == #foo ifTrue: [^ self knorz]. >> aSymbol == #bar ifTrue: [^ self berfp]. >> ^ false >> >> I think this is sufficient. > > Those ifTrue:'s quickly render your code unreadable or force you to extract chunks of your code into a separate method which can impair legibility. If you need more than a few of these, you're circumventing the actual method dispatch by dispatching on identity manually. Why making such nonsense easier? If you're building a bytecode interpreter, fine, but in that case, metaprogramming or code generation is not too far fetched either. -t > >> >> Otherwise, use an IdentityDictionary? > > Ah, the good old Pharo-way of doing things. :D > > All-in-all, it looks as though we're slipping into another caseOf: vs no-caseOf: discussion. Let's not do that. > > > Levente > >> >> Best regards >> -Tobias > From commits at source.squeak.org Sun Mar 28 14:52:19 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sun, 28 Mar 2021 14:52:19 0000 Subject: [squeak-dev] The Inbox: Chronology-Tests-dtl.25.mcz Message-ID: David T. Lewis uploaded a new version of Chronology-Tests to project The Inbox: http://source.squeak.org/inbox/Chronology-Tests-dtl.25.mcz ==================== Summary ==================== Name: Chronology-Tests-dtl.25 Author: dtl Time: 28 March 2021, 10:52:19.196147 am UUID: c5ee558b-5ac5-4d89-812c-4cfd106b45e2 Ancestors: Chronology-Tests-dtl.24 Expect that "1 second" should be a synonym for "1 seconds" so that "5 second" does not answer one second. Likewise for minute, hour, etc. =============== Diff against Chronology-Tests-dtl.24 =============== Item was added: + ----- Method: DurationTest>>testDaysFromNumber (in category 'tests - from number') ----- + testDaysFromNumber + + self assert: 5 equals: 5 days asSeconds / 86400. + self assert: -5 equals: -5 days asSeconds / 86400. + self assert: 1 equals: 1 days asSeconds / 86400. + self assert: -1 equals: -1 days asSeconds / 86400. + self assert: 0 equals: 0 days asSeconds / 86400. + self assert: 1500 equals: 1.5 days asMilliSeconds / 86400. + self assert: -1500 equals: -1.5 days asMilliSeconds / 86400. + + self assert: 5 equals: 5 day asSeconds / 86400. + self assert: -5 equals: -5 day asSeconds / 86400. + self assert: 1 equals: 1 day asSeconds / 86400. + self assert: -1 equals: -1 day asSeconds / 86400. + self assert: 0 equals: 0 day asSeconds / 86400. + self assert: 1500 equals: 1.5 day asMilliSeconds / 86400. + self assert: -1500 equals: -1.5 day asMilliSeconds / 86400. + ! Item was added: + ----- Method: DurationTest>>testHoursFromNumber (in category 'tests - from number') ----- + testHoursFromNumber + + self assert: 5 equals: 5 hours asSeconds / 3600. + self assert: -5 equals: -5 hours asSeconds / 3600. + self assert: 1 equals: 1 hours asSeconds / 3600. + self assert: -1 equals: -1 hours asSeconds / 3600. + self assert: 0 equals: 0 hours asSeconds / 3600. + self assert: 1500 equals: 1.5 hours asMilliSeconds / 3600. + self assert: -1500 equals: -1.5 hours asMilliSeconds / 3600. + + self assert: 5 equals: 5 hour asSeconds / 3600. + self assert: -5 equals: -5 hour asSeconds / 3600. + self assert: 1 equals: 1 hour asSeconds / 3600. + self assert: -1 equals: -1 hour asSeconds / 3600. + self assert: 0 equals: 0 hour asSeconds / 3600. + self assert: 1500 equals: 1.5 hour asMilliSeconds / 3600. + self assert: -1500 equals: -1.5 hour asMilliSeconds / 3600. + ! Item was added: + ----- Method: DurationTest>>testMicroSecondsFromNumber (in category 'tests - from number') ----- + testMicroSecondsFromNumber + + self assert: 5 equals: 5 microSeconds asMicroSeconds. + self assert: -5 equals: -5 microSeconds asMicroSeconds. + self assert: 1 equals: 1 microSeconds asMicroSeconds. + self assert: -1 equals: -1 microSeconds asMicroSeconds. + self assert: 0 equals: 0 microSeconds asMicroSeconds. + self assert: 1500 equals: 1.5 microSeconds asNanoSeconds. + self assert: -1500 equals: -1.5 microSeconds asNanoSeconds. + + self assert: 5 equals: 5 microSecond asMicroSeconds. + self assert: -5 equals: -5 microSecond asMicroSeconds. + self assert: 1 equals: 1 microSecond asMicroSeconds. + self assert: -1 equals: -1 microSecond asMicroSeconds. + self assert: 0 equals: 0 microSecond asMicroSeconds. + self assert: 1500 equals: 1.5 microSecond asNanoSeconds. + self assert: -1500 equals: -1.5 microSecond asNanoSeconds. + ! Item was added: + ----- Method: DurationTest>>testMilliSecondsFromNumber (in category 'tests - from number') ----- + testMilliSecondsFromNumber + + self assert: 5 equals: 5 milliSeconds asMilliSeconds. + self assert: -5 equals: -5 milliSeconds asMilliSeconds. + self assert: 1 equals: 1 milliSeconds asMilliSeconds. + self assert: -1 equals: -1 milliSeconds asMilliSeconds. + self assert: 0 equals: 0 milliSeconds asMilliSeconds. + self assert: 1500 equals: 1.5 milliSeconds asMicroSeconds. + self assert: -1500 equals: -1.5 milliSeconds asMicroSeconds. + + self assert: 5 equals: 5 milliSecond asMilliSeconds. + self assert: -5 equals: -5 milliSecond asMilliSeconds. + self assert: 1 equals: 1 milliSecond asMilliSeconds. + self assert: -1 equals: -1 milliSecond asMilliSeconds. + self assert: 0 equals: 0 milliSecond asMilliSeconds. + self assert: 1500 equals: 1.5 milliSecond asMicroSeconds. + self assert: -1500 equals: -1.5 milliSecond asMicroSeconds. + ! Item was added: + ----- Method: DurationTest>>testMinutesFromNumber (in category 'tests - from number') ----- + testMinutesFromNumber + + self assert: 5 equals: 5 minutes asSeconds / 60. + self assert: -5 equals: -5 minutes asSeconds / 60. + self assert: 1 equals: 1 minutes asSeconds / 60. + self assert: -1 equals: -1 minutes asSeconds / 60. + self assert: 0 equals: 0 minutes asSeconds / 60. + self assert: 1500 equals: 1.5 minutes asMilliSeconds / 60. + self assert: -1500 equals: -1.5 minutes asMilliSeconds / 60. + + self assert: 5 equals: 5 minute asSeconds / 60. + self assert: -5 equals: -5 minute asSeconds / 60. + self assert: 1 equals: 1 minute asSeconds / 60. + self assert: -1 equals: -1 minute asSeconds / 60. + self assert: 0 equals: 0 minute asSeconds / 60. + self assert: 1500 equals: 1.5 minute asMilliSeconds / 60. + self assert: -1500 equals: -1.5 minute asMilliSeconds / 60. + ! Item was added: + ----- Method: DurationTest>>testNanoSecondsFromNumber (in category 'tests - from number') ----- + testNanoSecondsFromNumber + + self assert: 5 equals: 5 nanoSeconds asNanoSeconds. + self assert: -5 equals: -5 nanoSeconds asNanoSeconds. + self assert: 1 equals: 1 nanoSeconds asNanoSeconds. + self assert: -1 equals: -1 nanoSeconds asNanoSeconds. + self assert: 0 equals: 0 nanoSeconds asNanoSeconds. + + self assert: 5 equals: 5 nanoSecond asNanoSeconds. + self assert: -5 equals: -5 nanoSecond asNanoSeconds. + self assert: 1 equals: 1 nanoSecond asNanoSeconds. + self assert: -1 equals: -1 nanoSecond asNanoSeconds. + self assert: 0 equals: 0 nanoSecond asNanoSeconds. + ! Item was added: + ----- Method: DurationTest>>testSecondsFromNumber (in category 'tests - from number') ----- + testSecondsFromNumber + + self assert: 5 equals: 5 seconds asSeconds. + self assert: -5 equals: -5 seconds asSeconds. + self assert: 1 equals: 1 seconds asSeconds. + self assert: -1 equals: -1 seconds asSeconds. + self assert: 0 equals: 0 seconds asSeconds. + self assert: 1500 equals: 1.5 seconds asMilliSeconds. + self assert: -1500 equals: -1.5 seconds asMilliSeconds. + + self assert: 5 equals: 5 second asSeconds. + self assert: -5 equals: -5 second asSeconds. + self assert: 1 equals: 1 second asSeconds. + self assert: -1 equals: -1 second asSeconds. + self assert: 0 equals: 0 second asSeconds. + self assert: 1500 equals: 1.5 second asMilliSeconds. + self assert: -1500 equals: -1.5 second asMilliSeconds. + ! Item was added: + ----- Method: DurationTest>>testWeeksFromNumber (in category 'tests - from number') ----- + testWeeksFromNumber + + self assert: 5 equals: 5 weeks asSeconds / 604800. + self assert: -5 equals: -5 weeks asSeconds / 604800. + self assert: 1 equals: 1 weeks asSeconds / 604800. + self assert: -1 equals: -1 weeks asSeconds / 604800. + self assert: 0 equals: 0 weeks asSeconds / 604800. + self assert: 1500 equals: 1.5 weeks asMilliSeconds / 604800. + self assert: -1500 equals: -1.5 weeks asMilliSeconds / 604800. + + self assert: 5 equals: 5 week asSeconds / 604800. + self assert: -5 equals: -5 week asSeconds / 604800. + self assert: 1 equals: 1 week asSeconds / 604800. + self assert: -1 equals: -1 week asSeconds / 604800. + self assert: 0 equals: 0 week asSeconds / 604800. + self assert: 1500 equals: 1.5 week asMilliSeconds / 604800. + self assert: -1500 equals: -1.5 week asMilliSeconds / 604800. + ! From commits at source.squeak.org Sun Mar 28 14:52:56 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Sun, 28 Mar 2021 14:52:56 0000 Subject: [squeak-dev] The Inbox: Chronology-Core-dtl.66.mcz Message-ID: A new version of Chronology-Core was added to project The Inbox: http://source.squeak.org/inbox/Chronology-Core-dtl.66.mcz ==================== Summary ==================== Name: Chronology-Core-dtl.66 Author: dtl Time: 28 March 2021, 10:52:56.0001 am UUID: 9695afba-0eaf-49ab-8d2e-177f089f1d04 Ancestors: Chronology-Core-dtl.65 Let "1 second" be a synonym for "1 seconds" so that "5 second" does not answer one second. Likewise for minute, hour, etc. =============== Diff against Chronology-Core-dtl.65 =============== Item was changed: ----- Method: Number>>day (in category '*chronology-core') ----- day + ^ self days! - ^ self sign days! Item was changed: ----- Method: Number>>hour (in category '*chronology-core') ----- hour + ^ self hours - ^ self sign hours ! Item was changed: ----- Method: Number>>microSecond (in category '*chronology-core') ----- microSecond + ^ self microSeconds! - ^ self sign microSeconds! Item was changed: ----- Method: Number>>milliSecond (in category '*chronology-core') ----- milliSecond + ^ self milliSeconds - ^ self sign milliSeconds ! Item was changed: ----- Method: Number>>minute (in category '*chronology-core') ----- minute + ^ self minutes - ^ self sign minutes ! Item was changed: ----- Method: Number>>nanoSecond (in category '*chronology-core') ----- nanoSecond + ^ self nanoSeconds - ^ self sign nanoSeconds ! Item was changed: ----- Method: Number>>second (in category '*chronology-core') ----- second + ^ self seconds - ^ self sign seconds ! Item was changed: ----- Method: Number>>week (in category '*chronology-core') ----- week + ^ self weeks - ^ self sign weeks ! From lewis at mail.msen.com Sun Mar 28 14:59:54 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sun, 28 Mar 2021 10:59:54 -0400 Subject: [squeak-dev] The Inbox: Chronology-Tests-dtl.25.mcz In-Reply-To: References: Message-ID: <20210328145954.GA60671@shell.msen.com> In earlier discussion, I believe we had general consensus that having "5 second" answer 1 second was not good, and also that simply treating #second and synonym for #second would be the preferred approach. These tests document the expectations, and Chronology-Core-dtl.66 implements the change. Both in the inbox now, and if no further comment I'll move to trunk in a few days. Dave On Sun, Mar 28, 2021 at 02:52:19PM +0000, commits at source.squeak.org wrote: > David T. Lewis uploaded a new version of Chronology-Tests to project The Inbox: > http://source.squeak.org/inbox/Chronology-Tests-dtl.25.mcz > > ==================== Summary ==================== > > Name: Chronology-Tests-dtl.25 > Author: dtl > Time: 28 March 2021, 10:52:19.196147 am > UUID: c5ee558b-5ac5-4d89-812c-4cfd106b45e2 > Ancestors: Chronology-Tests-dtl.24 > > Expect that "1 second" should be a synonym for "1 seconds" so that "5 second" does not answer one second. Likewise for minute, hour, etc. > > =============== Diff against Chronology-Tests-dtl.24 =============== > > Item was added: > + ----- Method: DurationTest>>testDaysFromNumber (in category 'tests - from number') ----- > + testDaysFromNumber > + > + self assert: 5 equals: 5 days asSeconds / 86400. > + self assert: -5 equals: -5 days asSeconds / 86400. > + self assert: 1 equals: 1 days asSeconds / 86400. > + self assert: -1 equals: -1 days asSeconds / 86400. > + self assert: 0 equals: 0 days asSeconds / 86400. > + self assert: 1500 equals: 1.5 days asMilliSeconds / 86400. > + self assert: -1500 equals: -1.5 days asMilliSeconds / 86400. > + > + self assert: 5 equals: 5 day asSeconds / 86400. > + self assert: -5 equals: -5 day asSeconds / 86400. > + self assert: 1 equals: 1 day asSeconds / 86400. > + self assert: -1 equals: -1 day asSeconds / 86400. > + self assert: 0 equals: 0 day asSeconds / 86400. > + self assert: 1500 equals: 1.5 day asMilliSeconds / 86400. > + self assert: -1500 equals: -1.5 day asMilliSeconds / 86400. > + ! > > Item was added: > + ----- Method: DurationTest>>testHoursFromNumber (in category 'tests - from number') ----- > + testHoursFromNumber > + > + self assert: 5 equals: 5 hours asSeconds / 3600. > + self assert: -5 equals: -5 hours asSeconds / 3600. > + self assert: 1 equals: 1 hours asSeconds / 3600. > + self assert: -1 equals: -1 hours asSeconds / 3600. > + self assert: 0 equals: 0 hours asSeconds / 3600. > + self assert: 1500 equals: 1.5 hours asMilliSeconds / 3600. > + self assert: -1500 equals: -1.5 hours asMilliSeconds / 3600. > + > + self assert: 5 equals: 5 hour asSeconds / 3600. > + self assert: -5 equals: -5 hour asSeconds / 3600. > + self assert: 1 equals: 1 hour asSeconds / 3600. > + self assert: -1 equals: -1 hour asSeconds / 3600. > + self assert: 0 equals: 0 hour asSeconds / 3600. > + self assert: 1500 equals: 1.5 hour asMilliSeconds / 3600. > + self assert: -1500 equals: -1.5 hour asMilliSeconds / 3600. > + ! > > Item was added: > + ----- Method: DurationTest>>testMicroSecondsFromNumber (in category 'tests - from number') ----- > + testMicroSecondsFromNumber > + > + self assert: 5 equals: 5 microSeconds asMicroSeconds. > + self assert: -5 equals: -5 microSeconds asMicroSeconds. > + self assert: 1 equals: 1 microSeconds asMicroSeconds. > + self assert: -1 equals: -1 microSeconds asMicroSeconds. > + self assert: 0 equals: 0 microSeconds asMicroSeconds. > + self assert: 1500 equals: 1.5 microSeconds asNanoSeconds. > + self assert: -1500 equals: -1.5 microSeconds asNanoSeconds. > + > + self assert: 5 equals: 5 microSecond asMicroSeconds. > + self assert: -5 equals: -5 microSecond asMicroSeconds. > + self assert: 1 equals: 1 microSecond asMicroSeconds. > + self assert: -1 equals: -1 microSecond asMicroSeconds. > + self assert: 0 equals: 0 microSecond asMicroSeconds. > + self assert: 1500 equals: 1.5 microSecond asNanoSeconds. > + self assert: -1500 equals: -1.5 microSecond asNanoSeconds. > + ! > > Item was added: > + ----- Method: DurationTest>>testMilliSecondsFromNumber (in category 'tests - from number') ----- > + testMilliSecondsFromNumber > + > + self assert: 5 equals: 5 milliSeconds asMilliSeconds. > + self assert: -5 equals: -5 milliSeconds asMilliSeconds. > + self assert: 1 equals: 1 milliSeconds asMilliSeconds. > + self assert: -1 equals: -1 milliSeconds asMilliSeconds. > + self assert: 0 equals: 0 milliSeconds asMilliSeconds. > + self assert: 1500 equals: 1.5 milliSeconds asMicroSeconds. > + self assert: -1500 equals: -1.5 milliSeconds asMicroSeconds. > + > + self assert: 5 equals: 5 milliSecond asMilliSeconds. > + self assert: -5 equals: -5 milliSecond asMilliSeconds. > + self assert: 1 equals: 1 milliSecond asMilliSeconds. > + self assert: -1 equals: -1 milliSecond asMilliSeconds. > + self assert: 0 equals: 0 milliSecond asMilliSeconds. > + self assert: 1500 equals: 1.5 milliSecond asMicroSeconds. > + self assert: -1500 equals: -1.5 milliSecond asMicroSeconds. > + ! > > Item was added: > + ----- Method: DurationTest>>testMinutesFromNumber (in category 'tests - from number') ----- > + testMinutesFromNumber > + > + self assert: 5 equals: 5 minutes asSeconds / 60. > + self assert: -5 equals: -5 minutes asSeconds / 60. > + self assert: 1 equals: 1 minutes asSeconds / 60. > + self assert: -1 equals: -1 minutes asSeconds / 60. > + self assert: 0 equals: 0 minutes asSeconds / 60. > + self assert: 1500 equals: 1.5 minutes asMilliSeconds / 60. > + self assert: -1500 equals: -1.5 minutes asMilliSeconds / 60. > + > + self assert: 5 equals: 5 minute asSeconds / 60. > + self assert: -5 equals: -5 minute asSeconds / 60. > + self assert: 1 equals: 1 minute asSeconds / 60. > + self assert: -1 equals: -1 minute asSeconds / 60. > + self assert: 0 equals: 0 minute asSeconds / 60. > + self assert: 1500 equals: 1.5 minute asMilliSeconds / 60. > + self assert: -1500 equals: -1.5 minute asMilliSeconds / 60. > + ! > > Item was added: > + ----- Method: DurationTest>>testNanoSecondsFromNumber (in category 'tests - from number') ----- > + testNanoSecondsFromNumber > + > + self assert: 5 equals: 5 nanoSeconds asNanoSeconds. > + self assert: -5 equals: -5 nanoSeconds asNanoSeconds. > + self assert: 1 equals: 1 nanoSeconds asNanoSeconds. > + self assert: -1 equals: -1 nanoSeconds asNanoSeconds. > + self assert: 0 equals: 0 nanoSeconds asNanoSeconds. > + > + self assert: 5 equals: 5 nanoSecond asNanoSeconds. > + self assert: -5 equals: -5 nanoSecond asNanoSeconds. > + self assert: 1 equals: 1 nanoSecond asNanoSeconds. > + self assert: -1 equals: -1 nanoSecond asNanoSeconds. > + self assert: 0 equals: 0 nanoSecond asNanoSeconds. > + ! > > Item was added: > + ----- Method: DurationTest>>testSecondsFromNumber (in category 'tests - from number') ----- > + testSecondsFromNumber > + > + self assert: 5 equals: 5 seconds asSeconds. > + self assert: -5 equals: -5 seconds asSeconds. > + self assert: 1 equals: 1 seconds asSeconds. > + self assert: -1 equals: -1 seconds asSeconds. > + self assert: 0 equals: 0 seconds asSeconds. > + self assert: 1500 equals: 1.5 seconds asMilliSeconds. > + self assert: -1500 equals: -1.5 seconds asMilliSeconds. > + > + self assert: 5 equals: 5 second asSeconds. > + self assert: -5 equals: -5 second asSeconds. > + self assert: 1 equals: 1 second asSeconds. > + self assert: -1 equals: -1 second asSeconds. > + self assert: 0 equals: 0 second asSeconds. > + self assert: 1500 equals: 1.5 second asMilliSeconds. > + self assert: -1500 equals: -1.5 second asMilliSeconds. > + ! > > Item was added: > + ----- Method: DurationTest>>testWeeksFromNumber (in category 'tests - from number') ----- > + testWeeksFromNumber > + > + self assert: 5 equals: 5 weeks asSeconds / 604800. > + self assert: -5 equals: -5 weeks asSeconds / 604800. > + self assert: 1 equals: 1 weeks asSeconds / 604800. > + self assert: -1 equals: -1 weeks asSeconds / 604800. > + self assert: 0 equals: 0 weeks asSeconds / 604800. > + self assert: 1500 equals: 1.5 weeks asMilliSeconds / 604800. > + self assert: -1500 equals: -1.5 weeks asMilliSeconds / 604800. > + > + self assert: 5 equals: 5 week asSeconds / 604800. > + self assert: -5 equals: -5 week asSeconds / 604800. > + self assert: 1 equals: 1 week asSeconds / 604800. > + self assert: -1 equals: -1 week asSeconds / 604800. > + self assert: 0 equals: 0 week asSeconds / 604800. > + self assert: 1500 equals: 1.5 week asMilliSeconds / 604800. > + self assert: -1500 equals: -1.5 week asMilliSeconds / 604800. > + ! > > From Christoph.Thiede at student.hpi.uni-potsdam.de Sun Mar 28 15:05:03 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sun, 28 Mar 2021 15:05:03 +0000 Subject: [squeak-dev] Problems with #caseError In-Reply-To: <20210328140231.GA46725@shell.msen.com> References: <69dd1997c7844439bda1b7b15e40cc01@student.hpi.uni-potsdam.de> <7cb95adc46fc4e1294f93babc605f2c2@student.hpi.uni-potsdam.de> <32f9227ca5a2496485461b9a644cccc6@student.hpi.uni-potsdam.de> <91153db2ef7845cc875bc038dcb7dca2@student.hpi.uni-potsdam.de> <62981f221bd34220ba22fda263080cd0@student.hpi.uni-potsdam.de> <1616932284132-0.post@n4.nabble.com>,<20210328140231.GA46725@shell.msen.com> Message-ID: Hi Dave, I am sorry for the confusion. It took me some time to finally find the right thread, but apparently, Nicolas already has merged this changeset last May via Compiler-nice.430. (Thank you, Nicolas!) Because the thread when I mentioned it here ended with Marcel's advice to merge the changeset later, I had assumed that it would still be to do. I could now, once again, point to the advantages of a GitHub-like issue and PR tracker where you could close and auto-reference threads from each other, but I guess I have already done this often enough. :-) Maybe it would be a good idea to (manually) send a short confirmation message directly to the thread where a changeset has been posted when someone finds the time to merge it. For inbox versions, this process is easier because they are arranged in Monticello with a clear identifier ... Again, sorry for wasting your time! Nevertheless, your thoughts on #caseError: (with argument) and my #allLiterals observation are highly welcome. :-) > I should note that it took me quite some time to figure out the context of this message. I have no clue why the Nabble link does not point to the exact conversation. Usually, it does as far as I know. I also think it would be an improvement if replies that are sent via Nabble would have attached the entire conversation. Are we in control of the Nabble sources to make such a change? Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von David T. Lewis Gesendet: Sonntag, 28. März 2021 16:02:31 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] Problems with #caseError Hi Christoph, On Sun, Mar 28, 2021 at 06:51:24AM -0500, Christoph Thiede wrote: > Hi all, > > this is a small reminder, this changeset is still pending review. Would it > be possible to get this merged before the next release? :-) > Perhaps you can update the changes and maybe submit back to the inbox? Looking at the change set, I see that your change to Object is already in the image, and there have been more recent changes to MessageNode that presumably would require merging. I expect that the remaining change would be a small update to the Compiler package. I should note that it took me quite some time to figure out the context of this message. I think it is because of this: > -- > Sent from: http://forum.world.st/Squeak-Dev-f45488.html > Apparently you send this as a reply from the forum, but the resulting email here on the list provided no context for the thread you were discussing. I was unable to find any prior emails with this subject in the recent archives. I finally figured it out when I noticed the "Sent from:" line at the bottom of your message. Dave -------------- next part -------------- An HTML attachment was scrubbed... URL: From Christoph.Thiede at student.hpi.uni-potsdam.de Sun Mar 28 15:22:12 2021 From: Christoph.Thiede at student.hpi.uni-potsdam.de (Thiede, Christoph) Date: Sun, 28 Mar 2021 15:22:12 +0000 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: <3E24C1AF-9FD7-41A9-A6E9-999C02E196BD@gmx.de> References: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> , <3E24C1AF-9FD7-41A9-A6E9-999C02E196BD@gmx.de> Message-ID: <43ca226bc9e949528fa82cbff0a991fa@student.hpi.uni-potsdam.de> Hi all, > > @Levente: Glad you like it! Regarding arguments, did you read [2]? It's already a bit older but I have not continued working on this since I'm afraid have not got any feedback on the proposal. :-) > > I had a look at the change set. It looks good but seems to lack decompiler-related changes which I think are necessary to keep the decompiler working. Thank you! I'll put this onto my to-do list again (but will have a short vacation first). :-) > If you need more than a few of these, you're circumventing the actual method dispatch by dispatching on identity manually. Dispatching on identity is not possible always, I guess? Consider the example in PreferenceBrowserMorph I mentioned earlier (I think we have many of them in Morphic). I don't think something like an extension method Character >> #doKeyboardActionForPreferenceBrowserMorph: would be an appropriate refactoring here. ;-) Still, I see your point that #caseOf:[otherwise:] *can* be a code smell and point to a necessary refactoring in the form of dispatching. If I would read something like "anObject class caseOf: {...", I would definitively dislike that, too, of course. Nevertheless, I think that dispatching solutions do not scale well for small snippets in all situations. Unless I find multiple instances of such a coding smell, I would hesitate to apply a fancy pattern (Simple Design, DTSTTCPW, YAGNI, Rule of Three, etc.). In such situations, I think #caseOf:[otherwise:] is just a helper to write less duplicated code. And LBNL, Levente's new proposal shows additional use cases for #caseOf: that go beyond simple identity dispatching. :-) btw: > If you're building a bytecode interpreter, fine, but in that case, metaprogramming or code generation is not too far fetched either. Is code generation really advisable whenever you have an alternative? I don't have experience with it, but when I hear "generation" I always have to think of "synchronization issues", too ... You are building derived structures that either need to be kept in sync with the originating structure, or that have to be considered as read-only which makes tooling even harder. Or is this only my impression? Best, Christoph ________________________________ Von: Squeak-dev im Auftrag von Tobias Pape Gesendet: Sonntag, 28. März 2021 16:48:22 An: The general-purpose Squeak developers list Betreff: Re: [squeak-dev] #identityCaseOf: > On 28. Mar 2021, at 16:03, Levente Uzonyi wrote: > > On Sun, 28 Mar 2021, Tobias Pape wrote: > >> Hi >> >> >>> On 28. Mar 2021, at 07:12, tim Rowledge wrote: >>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >>>> Hi all, >>>> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? >>> I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." >> >> Exactly. >> If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. >> (as in the case of #update: >> >> update: aSymbol >> >> aSymbol == #foo ifTrue: [^ self knorz]. >> aSymbol == #bar ifTrue: [^ self berfp]. >> ^ false >> >> I think this is sufficient. > > Those ifTrue:'s quickly render your code unreadable or force you to extract chunks of your code into a separate method which can impair legibility. If you need more than a few of these, you're circumventing the actual method dispatch by dispatching on identity manually. Why making such nonsense easier? If you're building a bytecode interpreter, fine, but in that case, metaprogramming or code generation is not too far fetched either. -t > >> >> Otherwise, use an IdentityDictionary? > > Ah, the good old Pharo-way of doing things. :D > > All-in-all, it looks as though we're slipping into another caseOf: vs no-caseOf: discussion. Let's not do that. > > > Levente > >> >> Best regards >> -Tobias > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Sun Mar 28 15:44:55 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sun, 28 Mar 2021 11:44:55 -0400 Subject: [squeak-dev] Problems with #caseError In-Reply-To: References: <69dd1997c7844439bda1b7b15e40cc01@student.hpi.uni-potsdam.de> <7cb95adc46fc4e1294f93babc605f2c2@student.hpi.uni-potsdam.de> <32f9227ca5a2496485461b9a644cccc6@student.hpi.uni-potsdam.de> <91153db2ef7845cc875bc038dcb7dca2@student.hpi.uni-potsdam.de> <62981f221bd34220ba22fda263080cd0@student.hpi.uni-potsdam.de> Message-ID: <20210328154455.GA68615@shell.msen.com> On Sun, Mar 28, 2021 at 03:05:03PM +0000, Thiede, Christoph wrote: > Hi Dave, > > > I am sorry for the confusion. It took me some time to finally find the right thread, but apparently, Nicolas already has merged this changeset last May via Compiler-nice.430. (Thank you, Nicolas!) Because the thread when I mentioned it here ended with Marcel's advice to merge the changeset later, I had assumed that it would still be to do. > It's no problem at all, I only wanted to explain it because it was not obvious why the message context was lost, so I figured that if it was confusing to me then it would probably be confusing to other people too :-) Dave From leves at caesar.elte.hu Sun Mar 28 16:08:25 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Sun, 28 Mar 2021 18:08:25 +0200 (CEST) Subject: [squeak-dev] #identityCaseOf: In-Reply-To: References: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> Message-ID: On Sun, 28 Mar 2021, Tobias Pape wrote: > > >> On 28. Mar 2021, at 16:03, Levente Uzonyi wrote: >> >> On Sun, 28 Mar 2021, Tobias Pape wrote: >> >>> Hi >>> >>> >>>> On 28. Mar 2021, at 07:12, tim Rowledge wrote: >>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >>>>> Hi all, >>>>> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? >>>> I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." >>> >>> Exactly. >>> If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. >>> (as in the case of #update: >>> >>> update: aSymbol >>> >>> aSymbol == #foo ifTrue: [^ self knorz]. >>> aSymbol == #bar ifTrue: [^ self berfp]. >>> ^ false >>> >>> I think this is sufficient. >> >> Those ifTrue:'s quickly render your code unreadable or force you to extract chunks of your code into a separate method which can impair legibility. >> >>> >>> Otherwise, use an IdentityDictionary? >> >> Ah, the good old Pharo-way of doing things. :D > > what? > -t I meant the pattern that became popular in Pharo to replace caseOf:. Your example would be something like update: aSymbol ^(Dictionary newFrom: { #foo -> [ self knorz ]. #bar -> [ self berfp ] }) at: aSymbol ifPresent: [ :block | block value ] ifAbsent: [ false ] There's also another variant[1] which uses an array and #detect:. Levente [1] http://forum.world.st/could-we-agree-to-remove-caseOf-and-caseOf-otherwise-td3302475.html > >> >> All-in-all, it looks as though we're slipping into another caseOf: vs no-caseOf: discussion. Let's not do that. >> >> >> Levente >> >>> >>> Best regards >>> -Tobias From m at jaromir.net Sun Mar 28 16:13:37 2021 From: m at jaromir.net (Jaromir Matas) Date: Sun, 28 Mar 2021 11:13:37 -0500 (CDT) Subject: [squeak-dev] The Inbox: Chronology-Core-dtl.66.mcz In-Reply-To: References: Message-ID: <1616948017696-0.post@n4.nabble.com> Hi, great! Would it be a bad idea to have milliseconds instead (or on top) of milliSeconds? Etc. ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From leves at caesar.elte.hu Sun Mar 28 16:14:00 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Sun, 28 Mar 2021 18:14:00 +0200 (CEST) Subject: [squeak-dev] #identityCaseOf: In-Reply-To: <3E24C1AF-9FD7-41A9-A6E9-999C02E196BD@gmx.de> References: <159E9F02-70D8-4BFA-9428-BBDF91A78B00@gmx.de> <3E24C1AF-9FD7-41A9-A6E9-999C02E196BD@gmx.de> Message-ID: On Sun, 28 Mar 2021, Tobias Pape wrote: > > >> On 28. Mar 2021, at 16:03, Levente Uzonyi wrote: >> >> On Sun, 28 Mar 2021, Tobias Pape wrote: >> >>> Hi >>> >>> >>>> On 28. Mar 2021, at 07:12, tim Rowledge wrote: >>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph wrote: >>>>> Hi all, >>>>> the proposal is in the title. :-) Do you think we could need something like #identityCaseOf:[otherwise:], analogously to #caseOf:[otherwise:], on Object? >>>> I would go with 'not'. I'm not a fan of #caseOf: either. Far too like C. Slippery slope to "oooh, let's have thing.ivar.ivar to be like structs." >>> >>> Exactly. >>> If you need something like that, there's either a missing polymorphic abstraction, or a few ifTrue:'s are sufficient. >>> (as in the case of #update: >>> >>> update: aSymbol >>> >>> aSymbol == #foo ifTrue: [^ self knorz]. >>> aSymbol == #bar ifTrue: [^ self berfp]. >>> ^ false >>> >>> I think this is sufficient. >> >> Those ifTrue:'s quickly render your code unreadable or force you to extract chunks of your code into a separate method which can impair legibility. > > > If you need more than a few of these, you're circumventing the actual method dispatch > by dispatching on identity manually. > Why making such nonsense easier? So, it's the caseOf: vs no caseOf: discussion again. I'll just copy a link to Eliot's example here: http://forum.world.st/could-we-agree-to-remove-caseOf-and-caseOf-otherwise-tp3302475p3307627.html Levente > > If you're building a bytecode interpreter, fine, but in that case, metaprogramming or code generation is not too far fetched either. > > -t > >> >>> >>> Otherwise, use an IdentityDictionary? >> >> Ah, the good old Pharo-way of doing things. :D >> >> All-in-all, it looks as though we're slipping into another caseOf: vs no-caseOf: discussion. Let's not do that. >> >> >> Levente >> >>> >>> Best regards >>> -Tobias >> From tim at rowledge.org Sun Mar 28 17:07:58 2021 From: tim at rowledge.org (tim Rowledge) Date: Sun, 28 Mar 2021 10:07:58 -0700 Subject: [squeak-dev] #identityCaseOf: In-Reply-To: <9d7b625fce5847c187d77d373430ceb9@student.hpi.uni-potsdam.de> References: <9d7b625fce5847c187d77d373430ceb9@student.hpi.uni-potsdam.de> Message-ID: > On 2021-03-28, at 4:09 AM, Thiede, Christoph wrote: > > @Tim: > > > Far too like C. > > Again, why please? :-) I'm not a big fan of C either, but IMO switch/select/case is not the worst concept when it allows you to eliminate some duplication. It (both C and caseOf*) has its uses but my practical issue with caseOf* in Smalltalk is that I keep (very subjective and personal experience dependant) seeing it get used in ways that completely sidestep Smalltalk and implement bad C idiom. A bit like isKindOf: and isBlahClass. e.g. foo class caseOf: { [Rabbit] -> [foo doRabbitThing]. [Fox] -> [foo doFoxThing]} ... which of course merely (badly) replicates class lookup/inheritance/message-sending. It suggests a writer that cannot escape the mental prison of C-like assault coding. isKindOf: is a useful meta-programming idiom that I've seen used inside inner loops to do the same sort of not-message-sending. I've even had people try to justify is on the grounds that "sending messages is so slow and I want ot avoid it", which is just nuts. isBlahClass is almost as horrible but at least has the excuse of (hopefully) being part of a not yet completed cleaning of other nastiness. Part of the problem is that language flexibility always ends up being a tool that lets annoying people write bad FORTRAN in any language. And then somebody has to spend a too large fraction of their life trying to fix it. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Useful random insult:- Not enough sense to come in out of the rain. From lewis at mail.msen.com Sun Mar 28 18:55:56 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sun, 28 Mar 2021 14:55:56 -0400 Subject: [squeak-dev] The Inbox: Chronology-Core-dtl.66.mcz In-Reply-To: <1616948017696-0.post@n4.nabble.com> References: <1616948017696-0.post@n4.nabble.com> Message-ID: <20210328185556.GA75142@shell.msen.com> On Sun, Mar 28, 2021 at 11:13:37AM -0500, Jaromir Matas wrote: > Hi, > great! > > Would it be a bad idea to have milliseconds instead (or on top) of > milliSeconds? Etc. > I would not want to bother with that. It would just add more stuff to the API, and the existing selector names are good enough. Dave From lewis at mail.msen.com Sun Mar 28 20:22:53 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sun, 28 Mar 2021 16:22:53 -0400 Subject: [squeak-dev] Extending the functionality of caseOf: (was: #identityCaseOf:) In-Reply-To: References: Message-ID: <20210328202253.GA99661@shell.msen.com> Changing the subject to capture Levente's interesting idea of extending the functionality of caseOf: by passing the receiver object to the case blocks as a parameter. This idea seems good enough to deserve its own subject line. Dave On Sun, Mar 28, 2021 at 10:33:32AM +0200, Levente Uzonyi wrote: > Hi Christoph, > > I see some value having #identityCaseOf:, so +1 from me. > > But what would be a more interesting thing to explore (yes, I'm derailing > this conversation now because the answer to your question is yes already > :)) is to extend the functionality of #caseOf:. > > For example, passing the object to the condition block (or even the result > block) could be useful: > > self someComplexExpression caseOf: { > [ 1 ] -> [ self success ] > [ :value | value odd ] -> [ :value | self processEvenValue: value - > 1 ]. > [ :value | true "it's even ] -> [ :value | self processEvenValue ] } > > There are two new things in the example: > - the value of self someComplexExpression is optionally passed to the > blocks. Yes, that could be done by creating a temporary variable. The > compiler could do exactly that behind the scenes. > - when the value is passed to the matcher block, possibilities are greatly > extended. For example, it could even reproduce #identityCaseOf: > > foo caseOf: { > [ :o | o == #foo ] -> [ self foo ]. > [ :o | o == #bar ] -> [ self bar ] } > > The same thing could be done with the otherwise block too: > > self foo > caseOf: { ... } > otherwise: [ :value | value ] > > > Levente > From asqueaker at gmail.com Sun Mar 28 22:26:42 2021 From: asqueaker at gmail.com (Chris Muller) Date: Sun, 28 Mar 2021 17:26:42 -0500 Subject: [squeak-dev] Extending the functionality of caseOf: (was: #identityCaseOf:) In-Reply-To: <20210328202253.GA99661@shell.msen.com> References: <20210328202253.GA99661@shell.msen.com> Message-ID: > > For example, passing the object to the condition block (or even the > result > > block) could be useful: > > > > self someComplexExpression caseOf: { > > [ 1 ] -> [ self success ] > > [ :value | value odd ] -> [ :value | self processEvenValue: value > - > > 1 ]. > > [ :value | true "it's even ] -> [ :value | self processEvenValue ] > } > > > There are two new things in the example: > > - the value of self someComplexExpression is optionally passed to the > > blocks. Yes, that could be done by creating a temporary variable. Here's the version using a temporary and existing API (with an added identity-check). result := self someComplexExpression. true caseOf: { [result=1] -> [self success]. [result odd] -> [self processEvenValue: result-1]. [ result == identityValue ] -> [self processSomethingElse ]. [true] -> [self processEvenValue] } "true caseOf:" is my sneaky way to improve its flexibility. The suggested expansion of the API seems too dilute, not enough bang. > The > > compiler could do exactly that behind the scenes. > > - when the value is passed to the matcher block, possibilities are > greatly > > extended. The evaluation is done before any of the caseOf tests, so is it really extended with more expressive power? Or just a different syntax that moves the variable declaration from a temporary to the block arg? > For example, it could even reproduce #identityCaseOf: > > > > foo caseOf: { > > [ :o | o == #foo ] -> [ self foo ]. > > [ :o | o == #bar ] -> [ self bar ] } > > > > The same thing could be done with the otherwise block too: > > > > self foo > > caseOf: { ... } > > otherwise: [ :value | value ] > > > > > > Levente > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lewis at mail.msen.com Sun Mar 28 23:32:26 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Sun, 28 Mar 2021 19:32:26 -0400 Subject: [squeak-dev] Extending the functionality of caseOf: (was: #identityCaseOf:) In-Reply-To: References: <20210328202253.GA99661@shell.msen.com> Message-ID: <20210328233226.GA22906@shell.msen.com> On Sun, Mar 28, 2021 at 05:26:42PM -0500, Chris Muller wrote: > > Here's the version using a temporary and existing API (with an added > identity-check). > > result := self someComplexExpression. > true caseOf: > { [result=1] -> [self success]. > [result odd] -> [self processEvenValue: result-1]. > [ result == identityValue ] -> [self processSomethingElse ]. > [true] -> [self processEvenValue] } > > "true caseOf:" is my sneaky way to improve its flexibility. The suggested > expansion of the API seems too dilute, not enough bang. > I really like the true caseOf: approach. It seems obvious now that you point it out, but I never would have thought of it. Thanks :-) Dave From commits at source.squeak.org Mon Mar 29 08:23:28 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 29 Mar 2021 08:23:28 0000 Subject: [squeak-dev] The Trunk: System-tonyg.1224.mcz Message-ID: Tony Garnock-Jones uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-tonyg.1224.mcz ==================== Summary ==================== Name: System-tonyg.1224 Author: tonyg Time: 29 March 2021, 10:15:02.279821 am UUID: 9d897d72-46fc-4205-a27b-89c7a50ac104 Ancestors: System-mt.1223 Teach SystemOrganizer about multiple environments. =============== Diff against System-mt.1223 =============== Item was changed: Categorizer subclass: #SystemOrganizer + instanceVariableNames: 'environment' - instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'System-Support'! !SystemOrganizer commentStamp: '' prior: 0! My instances provide an organization for the classes in the system, just as a ClassOrganizer organizes the messages within a class. The only difference is the methods for fileIn/Out.! Item was changed: ----- Method: SystemOrganizer>>classesIn: (in category 'query') ----- classesIn: categoryName | classes | classes := OrderedCollection new. self categories withIndexCollect: [:cat :idx | (categoryName match: cat) ifTrue: [classes addAll: (self listAtCategoryNumber: idx)] ifFalse: [nil]]. + ^ classes collect: [:clsName | self environment classNamed: clsName]! - ^ classes collect: [:clsName | Smalltalk classNamed: clsName]! Item was changed: ----- Method: SystemOrganizer>>classify:under: (in category 'accessing') ----- classify: element under: newCategory | oldCategory class | self flag: #environments. "do we want notifications for classes in other environments?" oldCategory := self categoryOfElement: element. super classify: element under: newCategory. + class := self environment at: element ifAbsent: [^ self]. - class := Smalltalk at: element ifAbsent: [^ self]. self == SystemOrganization ifTrue: [ SystemChangeNotifier uniqueInstance class: class recategorizedFrom: oldCategory to: newCategory]! Item was changed: ----- Method: SystemOrganizer>>commentInventory: (in category 'query') ----- commentInventory: categoryName "SystemOrganization commentInventory: 'Morphic*'" | classes commentedClasses | classes := OrderedCollection new. self categories withIndexCollect: [:cat :idx | (categoryName match: cat) ifTrue: [classes addAll: (self listAtCategoryNumber: idx)] ifFalse: [nil]]. + commentedClasses := classes select: [:catCls | (self environment at: catCls) hasComment]. - commentedClasses := classes select: [:catCls | (Smalltalk at: catCls) hasComment]. ^ 'There are ' , classes size asString , ' classes in ' , categoryName , ' of which ' , commentedClasses size asString , ' have comments and ', (classes size - commentedClasses size) asString , ' do not yet have comments.' ! Item was added: + ----- Method: SystemOrganizer>>environment (in category 'accessing') ----- + environment + ^ environment ifNil: [Smalltalk globals]! Item was added: + ----- Method: SystemOrganizer>>environment: (in category 'accessing') ----- + environment: anEnvironment + environment := anEnvironment! Item was changed: ----- Method: SystemOrganizer>>fileOutCategory:on:initializing: (in category 'fileIn/Out') ----- fileOutCategory: category on: aFileStream initializing: aBool "Store on the file associated with aFileStream, all the traits and classes associated with the category and any requested shared pools in the right order." | first poolSet tempClass classes traits | traits := self orderedTraitsIn: category. classes := self superclassOrder: category. poolSet := Set new. classes do: [:class | class sharedPools do: [:eachPool | poolSet add: eachPool]]. poolSet size > 0 ifTrue: [ tempClass := Class new. tempClass shouldFileOutPools ifTrue: [ poolSet := poolSet select: [:aPool | + tempClass shouldFileOutPool: (self environment keyAtIdentityValue: aPool)]. - tempClass shouldFileOutPool: (Smalltalk globals keyAtIdentityValue: aPool)]. poolSet do: [:aPool | tempClass fileOutPool: aPool onFileStream: aFileStream]]]. first := true. traits, classes do: [:each | first ifTrue: [first := false] ifFalse: [aFileStream cr; nextPut: Character newPage; cr]. each fileOutOn: aFileStream moveSource: false toFile: 0 initializing: false]. aBool ifTrue: [classes do: [:cls | cls fileOutInitializerOn: aFileStream]].! Item was changed: ----- Method: SystemOrganizer>>orderedTraitsIn: (in category 'fileIn/Out') ----- orderedTraitsIn: category "Answer an OrderedCollection containing references to the traits in the category whose name is the argument, category (a string). The traits are ordered so they can be filed in." | behaviors traits | behaviors := (self listAtCategoryNamed: category asSymbol) + collect: [:title | self environment at: title]. - collect: [:title | Smalltalk at: title]. traits := behaviors reject: [:each | each isBehavior]. ^traits asArray sort: [:t1 :t2 | (t2 traitComposition allTraits includes: t1) or: [(t1 traitComposition allTraits includes: t2) not]]! Item was changed: ----- Method: SystemOrganizer>>removeMissingClasses (in category 'remove') ----- removeMissingClasses "Remove any class names that are no longer in the Smalltalk dictionary. Used for cleaning up after garbage collecting user-generated classes." "SystemOrganization removeMissingClasses" elementArray copy do: [:el | + (self environment includesKey: el) ifFalse: [self removeElement: el]]. - (Smalltalk includesKey: el) ifFalse: [self removeElement: el]]. ! Item was changed: ----- Method: SystemOrganizer>>superclassOrder: (in category 'fileIn/Out') ----- superclassOrder: category "Answer an OrderedCollection containing references to the classes in the category whose name is the argument, category (a string). The classes are ordered with superclasses first so they can be filed in." | behaviors classes | behaviors := (self listAtCategoryNamed: category asSymbol) + collect: [:title | self environment at: title]. - collect: [:title | Smalltalk at: title]. classes := behaviors select: [:each | each isBehavior]. ^ChangeSet superclassOrder: classes! From commits at source.squeak.org Mon Mar 29 08:23:41 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 29 Mar 2021 08:23:41 0000 Subject: [squeak-dev] The Trunk: Environments-tonyg.80.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Environments to project The Trunk: http://source.squeak.org/trunk/Environments-tonyg.80.mcz ==================== Summary ==================== Name: Environments-tonyg.80 Author: tonyg Time: 29 March 2021, 10:18:29.909437 am UUID: 53a02a38-aeab-425c-9157-4f243eafdd49 Ancestors: Environments-dtl.77 Take advantage of System-tonyg.1224, which teaches SystemOrganizer about environments. =============== Diff against Environments-dtl.77 =============== Item was changed: ----- Method: Environment>>initializeWithName: (in category 'initialize-release') ----- initializeWithName: aString | smalltalk | self initialize. info := EnvironmentInfo name: aString. + info organization environment: self. - . smalltalk := SmalltalkImage basicNew. smalltalk globals: self. declarations at: #Smalltalk put: smalltalk. declarations at: #Undeclared put: undeclared.! Item was changed: ----- Method: Environment>>initializeWithSystemDictionary: (in category 'initialize-release') ----- initializeWithSystemDictionary: old self initialize. info := EnvironmentInfo name: 'Smalltalk' organization: old organization packages: PackageOrganizer default. + info organization environment: self. old associationsDo: [:assc | declarations add: assc]. (old at: #Undeclared) associationsDo: [:assc | undeclared add: assc]. (declarations at: #Smalltalk) instVarNamed: 'globals' put: self. declarations at: #Undeclared put: undeclared.! From commits at source.squeak.org Mon Mar 29 08:23:50 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Mon, 29 Mar 2021 08:23:50 0000 Subject: [squeak-dev] The Trunk: Environments-tonyg.81.mcz Message-ID: Tony Garnock-Jones uploaded a new version of Environments to project The Trunk: http://source.squeak.org/trunk/Environments-tonyg.81.mcz ==================== Summary ==================== Name: Environments-tonyg.81 Author: tonyg Time: 29 March 2021, 10:20:10.069623 am UUID: 3b64bc37-b2d0-4b78-85fe-fa13775df713 Ancestors: Environments-tonyg.80 Repair EnvironmentRequest signal. =============== Diff against Environments-tonyg.80 =============== Item was changed: ----- Method: EnvironmentRequest>>defaultAction (in category 'exceptionDescription') ----- defaultAction | all environment | all := Environment allInstances. + environment := UIManager default + chooseFrom: (all collect: [:ea | ea printString]) + values: all. - environment := UIManager default chooseFrom: all values: all. self resume: environment.! From marcel.taeumel at hpi.de Mon Mar 29 08:36:50 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 29 Mar 2021 10:36:50 +0200 Subject: [squeak-dev] The Trunk: System-tonyg.1224.mcz In-Reply-To: References: Message-ID: Hi Tony. I suppose that the idea was that every environment has its own system organization. By adding a back reference from organization to environment, there is still no support of "multiple" environments. Do you plan to change this dynamically? If so, why? :-) Would you sketch an example? Best, Marcel Am 29.03.2021 10:23:41 schrieb commits at source.squeak.org : Tony Garnock-Jones uploaded a new version of System to project The Trunk: http://source.squeak.org/trunk/System-tonyg.1224.mcz ==================== Summary ==================== Name: System-tonyg.1224 Author: tonyg Time: 29 March 2021, 10:15:02.279821 am UUID: 9d897d72-46fc-4205-a27b-89c7a50ac104 Ancestors: System-mt.1223 Teach SystemOrganizer about multiple environments. =============== Diff against System-mt.1223 =============== Item was changed: Categorizer subclass: #SystemOrganizer + instanceVariableNames: 'environment' - instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'System-Support'! !SystemOrganizer commentStamp: '' prior: 0! My instances provide an organization for the classes in the system, just as a ClassOrganizer organizes the messages within a class. The only difference is the methods for fileIn/Out.! Item was changed: ----- Method: SystemOrganizer>>classesIn: (in category 'query') ----- classesIn: categoryName | classes | classes := OrderedCollection new. self categories withIndexCollect: [:cat :idx | (categoryName match: cat) ifTrue: [classes addAll: (self listAtCategoryNumber: idx)] ifFalse: [nil]]. + ^ classes collect: [:clsName | self environment classNamed: clsName]! - ^ classes collect: [:clsName | Smalltalk classNamed: clsName]! Item was changed: ----- Method: SystemOrganizer>>classify:under: (in category 'accessing') ----- classify: element under: newCategory | oldCategory class | self flag: #environments. "do we want notifications for classes in other environments?" oldCategory := self categoryOfElement: element. super classify: element under: newCategory. + class := self environment at: element ifAbsent: [^ self]. - class := Smalltalk at: element ifAbsent: [^ self]. self == SystemOrganization ifTrue: [ SystemChangeNotifier uniqueInstance class: class recategorizedFrom: oldCategory to: newCategory]! Item was changed: ----- Method: SystemOrganizer>>commentInventory: (in category 'query') ----- commentInventory: categoryName "SystemOrganization commentInventory: 'Morphic*'" | classes commentedClasses | classes := OrderedCollection new. self categories withIndexCollect: [:cat :idx | (categoryName match: cat) ifTrue: [classes addAll: (self listAtCategoryNumber: idx)] ifFalse: [nil]]. + commentedClasses := classes select: [:catCls | (self environment at: catCls) hasComment]. - commentedClasses := classes select: [:catCls | (Smalltalk at: catCls) hasComment]. ^ 'There are ' , classes size asString , ' classes in ' , categoryName , ' of which ' , commentedClasses size asString , ' have comments and ', (classes size - commentedClasses size) asString , ' do not yet have comments.' ! Item was added: + ----- Method: SystemOrganizer>>environment (in category 'accessing') ----- + environment + ^ environment ifNil: [Smalltalk globals]! Item was added: + ----- Method: SystemOrganizer>>environment: (in category 'accessing') ----- + environment: anEnvironment + environment := anEnvironment! Item was changed: ----- Method: SystemOrganizer>>fileOutCategory:on:initializing: (in category 'fileIn/Out') ----- fileOutCategory: category on: aFileStream initializing: aBool "Store on the file associated with aFileStream, all the traits and classes associated with the category and any requested shared pools in the right order." | first poolSet tempClass classes traits | traits := self orderedTraitsIn: category. classes := self superclassOrder: category. poolSet := Set new. classes do: [:class | class sharedPools do: [:eachPool | poolSet add: eachPool]]. poolSet size > 0 ifTrue: [ tempClass := Class new. tempClass shouldFileOutPools ifTrue: [ poolSet := poolSet select: [:aPool | + tempClass shouldFileOutPool: (self environment keyAtIdentityValue: aPool)]. - tempClass shouldFileOutPool: (Smalltalk globals keyAtIdentityValue: aPool)]. poolSet do: [:aPool | tempClass fileOutPool: aPool onFileStream: aFileStream]]]. first := true. traits, classes do: [:each | first ifTrue: [first := false] ifFalse: [aFileStream cr; nextPut: Character newPage; cr]. each fileOutOn: aFileStream moveSource: false toFile: 0 initializing: false]. aBool ifTrue: [classes do: [:cls | cls fileOutInitializerOn: aFileStream]].! Item was changed: ----- Method: SystemOrganizer>>orderedTraitsIn: (in category 'fileIn/Out') ----- orderedTraitsIn: category "Answer an OrderedCollection containing references to the traits in the category whose name is the argument, category (a string). The traits are ordered so they can be filed in." | behaviors traits | behaviors := (self listAtCategoryNamed: category asSymbol) + collect: [:title | self environment at: title]. - collect: [:title | Smalltalk at: title]. traits := behaviors reject: [:each | each isBehavior]. ^traits asArray sort: [:t1 :t2 | (t2 traitComposition allTraits includes: t1) or: [(t1 traitComposition allTraits includes: t2) not]]! Item was changed: ----- Method: SystemOrganizer>>removeMissingClasses (in category 'remove') ----- removeMissingClasses "Remove any class names that are no longer in the Smalltalk dictionary. Used for cleaning up after garbage collecting user-generated classes." "SystemOrganization removeMissingClasses" elementArray copy do: [:el | + (self environment includesKey: el) ifFalse: [self removeElement: el]]. - (Smalltalk includesKey: el) ifFalse: [self removeElement: el]]. ! Item was changed: ----- Method: SystemOrganizer>>superclassOrder: (in category 'fileIn/Out') ----- superclassOrder: category "Answer an OrderedCollection containing references to the classes in the category whose name is the argument, category (a string). The classes are ordered with superclasses first so they can be filed in." | behaviors classes | behaviors := (self listAtCategoryNamed: category asSymbol) + collect: [:title | self environment at: title]. - collect: [:title | Smalltalk at: title]. classes := behaviors select: [:each | each isBehavior]. ^ChangeSet superclassOrder: classes! -------------- next part -------------- An HTML attachment was scrubbed... URL: From tonyg at leastfixedpoint.com Mon Mar 29 08:42:07 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Mon, 29 Mar 2021 10:42:07 +0200 Subject: [squeak-dev] The Trunk: System-tonyg.1224.mcz In-Reply-To: References: Message-ID: <505531b9-9ee1-8c5e-42bc-d48d6952b416@leastfixedpoint.com> On 3/29/21 10:36 AM, Marcel Taeumel wrote: > I suppose that the idea was that every environment has its own system > organization. Exactly. They already do: but the problem is that doing anything with the resulting SystemOrganizer resulted in changes to *Smalltalk globals*! So this allows the per-Environment organizers to scope their effects correctly. > By adding a back reference from organization to > environment, there is still no support of "multiple" environments. Do > you plan to change this dynamically? If so, why? :-) Would you sketch an > example? It wouldn't change dynamically: instead, it is set at construction time. See related change Environments-tonyg.80. Regards, Tony From tonyg at leastfixedpoint.com Mon Mar 29 08:43:06 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Mon, 29 Mar 2021 10:43:06 +0200 Subject: [squeak-dev] The Trunk: System-tonyg.1224.mcz In-Reply-To: <505531b9-9ee1-8c5e-42bc-d48d6952b416@leastfixedpoint.com> References: <505531b9-9ee1-8c5e-42bc-d48d6952b416@leastfixedpoint.com> Message-ID: I noticed this, btw, removing a system category from a non-default environment, only to find the classes in Smalltalk were removed :-) On 3/29/21 10:42 AM, Tony Garnock-Jones wrote: > On 3/29/21 10:36 AM, Marcel Taeumel wrote: >> I suppose that the idea was that every environment has its own system >> organization. > > Exactly. They already do: but the problem is that doing anything with > the resulting SystemOrganizer resulted in changes to *Smalltalk > globals*! So this allows the per-Environment organizers to scope their > effects correctly. > >> By adding a back reference from organization to environment, there is >> still no support of "multiple" environments. Do you plan to change >> this dynamically? If so, why? :-) Would you sketch an example? > > It wouldn't change dynamically: instead, it is set at construction time. > See related change Environments-tonyg.80. > > Regards, >   Tony > From marcel.taeumel at hpi.de Mon Mar 29 08:51:05 2021 From: marcel.taeumel at hpi.de (Marcel Taeumel) Date: Mon, 29 Mar 2021 10:51:05 +0200 Subject: [squeak-dev] The Trunk: System-tonyg.1224.mcz In-Reply-To: References: <505531b9-9ee1-8c5e-42bc-d48d6952b416@leastfixedpoint.com> Message-ID: Ah, nevermind. You wanted to remove all those "Smalltalk classNamed:" references from SystemOrganizer. :-) Best, Marcel Am 29.03.2021 10:43:07 schrieb Tony Garnock-Jones : I noticed this, btw, removing a system category from a non-default environment, only to find the classes in Smalltalk were removed :-) On 3/29/21 10:42 AM, Tony Garnock-Jones wrote: > On 3/29/21 10:36 AM, Marcel Taeumel wrote: >> I suppose that the idea was that every environment has its own system >> organization. > > Exactly. They already do: but the problem is that doing anything with > the resulting SystemOrganizer resulted in changes to *Smalltalk > globals*! So this allows the per-Environment organizers to scope their > effects correctly. > >> By adding a back reference from organization to environment, there is >> still no support of "multiple" environments. Do you plan to change >> this dynamically? If so, why? :-) Would you sketch an example? > > It wouldn't change dynamically: instead, it is set at construction time. > See related change Environments-tonyg.80. > > Regards, > Tony > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tim at rowledge.org Mon Mar 29 16:39:02 2021 From: tim at rowledge.org (tim Rowledge) Date: Mon, 29 Mar 2021 09:39:02 -0700 Subject: [squeak-dev] Environments/namespaces (was Re: The Trunk: System-tonyg.1224.mcz) In-Reply-To: References: Message-ID: > On 2021-03-29, at 1:36 AM, Marcel Taeumel wrote: > Would you sketch an example? Leaving aside specifics of what Tony is doing, I'm still waiting for an explanation of what any of the environment stuff will actually do for me. None of my experiences with name space related things have ever been pleasurable. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Never underestimate the bandwidth of a station wagon full of tapes. From tonyg at leastfixedpoint.com Tue Mar 30 12:12:45 2021 From: tonyg at leastfixedpoint.com (Tony Garnock-Jones) Date: Tue, 30 Mar 2021 14:12:45 +0200 Subject: [squeak-dev] Nested Environments demo Message-ID: Hi all, I recorded a little screencast of the EnvironmentBrowser I've been playing with: https://www.youtube.com/watch?v=1UOyca5-72Y it's ~11 minutes long if you watch it at 1:1. In the description of the video is the outline that I was following as I recorded the talk. I'll paste it below as well. Cheers, Tony -=-=-=-=- [Here's the outline I was following as I recorded this talk.] Hi everyone. I'm Tony Garnock-Jones, it's March 30th 2021, and I'm going to walk through the experimentation I've been doing on nested Namespaces in Squeak Smalltalk. This work builds on Squeak's Environments, which I think are originally due to Colin Putney with some recent work by Jakob Reschke. I've made some small additions to Environment, and a little subclass called Namespace, which allows one to expose Environments via ordinary variable reference, if one so chooses. It doesn't change anything about how Environments work otherwise, so existing uses should remain unchanged. I've also added a variant of Browser that shows these accessible Environments in a hierarchy, and allows you to manage their imports and exports. Here it is. [Open an EnvironmentBrowser] [Navigate to EnvironmentBrowser] The tool is called EnvironmentBrowser, and it's a very thin veneer over the existing underlying Environment machinery. You can see that compared to the default browser, it has a couple of extra panels. This one [on the left] is a tree of environments. The idea is to take Environment's Instances as "well-known" roots for this tree: Environment wellKnownInstances Smalltalk is already in there, and at the moment there are no others. From the roots, we recursively scan each environment for globals that are also Environments. This scan is a part of Environment itself: [Navigate to Environment's namespaceTreeDo: method] This other panel [on the left, just below the tree of environments] shows the imports and exports of this environment. Here you can see that the default environment, Smalltalk, imports all its own bindings, so they're visible to its own classes, and exports all its bindings to other Environments that import from Smalltalk. [Create namespace NS1] [Create class String, extends Object, inst var length, category Demo] [Create accessors] printOn: aStream aStream nextPutAll: 'I am a ball of wool ', length, ' metres long' [class side] new: size ^ self new length: size [Proceed on the warning] [Open workspace in Smalltalk] String new: 3 [Open workspace in NS1] String new: 3 [Rename NS1 to Fabric] [Create namespace NS2] [Import Fabric with prefix Fabric] [Open workspace in NS2] String new: 3 FabricString new: 3 "Oh! It didn't work! We didn't export it from Fabric." [Export all from Fabric] [Try again - still doesn't work] [Redo the import] [Try again - works now!] There are still some issues with, I think, Environments themselves propagating changes to each other. Fabric String new: 3 [Unlink Fabric] Now we see: String new: 3 FabricString new: 3 Fabric String new: 3 "error on this, Fabric is missing" [Remove the policy importing Fabric to NS2] Didn't remove it. Still some bugs. From tim at rowledge.org Tue Mar 30 18:41:07 2021 From: tim at rowledge.org (tim Rowledge) Date: Tue, 30 Mar 2021 11:41:07 -0700 Subject: [squeak-dev] Stream nextPutAll: with an OrderedCollection go boom Message-ID: <28F42B3A-7A23-4DF3-82E6-A092B859486B@rowledge.org> I spotted a previous mention of this in the old maillist archives but it is still a current failure - (OrderedCollection streamContents: [:strm | strm nextPutAll: (OrderedCollection with: 1 ) ]) Boom! It's fine if we add asArray I'm suspicious of WriteStream>>#nextPutAll: making the assumption that SequenceableCollection>>#replaceFrom:to:with:startingAt: is always ok. Clearly not for OrderedCollection... Looks to me that we need to make OrderedCollection not pass the check for the 'fast path'? How about changing the #isBits test for a more capability oriented #canAcceptFastPathNextPut ? tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim A bug in the code is worth two in the documentation. From commits at source.squeak.org Tue Mar 30 19:39:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 30 Mar 2021 19:39:33 0000 Subject: [squeak-dev] The Trunk: Chronology-Tests-dtl.25.mcz Message-ID: David T. Lewis uploaded a new version of Chronology-Tests to project The Trunk: http://source.squeak.org/trunk/Chronology-Tests-dtl.25.mcz ==================== Summary ==================== Name: Chronology-Tests-dtl.25 Author: dtl Time: 28 March 2021, 10:52:19.196147 am UUID: c5ee558b-5ac5-4d89-812c-4cfd106b45e2 Ancestors: Chronology-Tests-dtl.24 Expect that "1 second" should be a synonym for "1 seconds" so that "5 second" does not answer one second. Likewise for minute, hour, etc. =============== Diff against Chronology-Tests-dtl.24 =============== Item was added: + ----- Method: DurationTest>>testDaysFromNumber (in category 'tests - from number') ----- + testDaysFromNumber + + self assert: 5 equals: 5 days asSeconds / 86400. + self assert: -5 equals: -5 days asSeconds / 86400. + self assert: 1 equals: 1 days asSeconds / 86400. + self assert: -1 equals: -1 days asSeconds / 86400. + self assert: 0 equals: 0 days asSeconds / 86400. + self assert: 1500 equals: 1.5 days asMilliSeconds / 86400. + self assert: -1500 equals: -1.5 days asMilliSeconds / 86400. + + self assert: 5 equals: 5 day asSeconds / 86400. + self assert: -5 equals: -5 day asSeconds / 86400. + self assert: 1 equals: 1 day asSeconds / 86400. + self assert: -1 equals: -1 day asSeconds / 86400. + self assert: 0 equals: 0 day asSeconds / 86400. + self assert: 1500 equals: 1.5 day asMilliSeconds / 86400. + self assert: -1500 equals: -1.5 day asMilliSeconds / 86400. + ! Item was added: + ----- Method: DurationTest>>testHoursFromNumber (in category 'tests - from number') ----- + testHoursFromNumber + + self assert: 5 equals: 5 hours asSeconds / 3600. + self assert: -5 equals: -5 hours asSeconds / 3600. + self assert: 1 equals: 1 hours asSeconds / 3600. + self assert: -1 equals: -1 hours asSeconds / 3600. + self assert: 0 equals: 0 hours asSeconds / 3600. + self assert: 1500 equals: 1.5 hours asMilliSeconds / 3600. + self assert: -1500 equals: -1.5 hours asMilliSeconds / 3600. + + self assert: 5 equals: 5 hour asSeconds / 3600. + self assert: -5 equals: -5 hour asSeconds / 3600. + self assert: 1 equals: 1 hour asSeconds / 3600. + self assert: -1 equals: -1 hour asSeconds / 3600. + self assert: 0 equals: 0 hour asSeconds / 3600. + self assert: 1500 equals: 1.5 hour asMilliSeconds / 3600. + self assert: -1500 equals: -1.5 hour asMilliSeconds / 3600. + ! Item was added: + ----- Method: DurationTest>>testMicroSecondsFromNumber (in category 'tests - from number') ----- + testMicroSecondsFromNumber + + self assert: 5 equals: 5 microSeconds asMicroSeconds. + self assert: -5 equals: -5 microSeconds asMicroSeconds. + self assert: 1 equals: 1 microSeconds asMicroSeconds. + self assert: -1 equals: -1 microSeconds asMicroSeconds. + self assert: 0 equals: 0 microSeconds asMicroSeconds. + self assert: 1500 equals: 1.5 microSeconds asNanoSeconds. + self assert: -1500 equals: -1.5 microSeconds asNanoSeconds. + + self assert: 5 equals: 5 microSecond asMicroSeconds. + self assert: -5 equals: -5 microSecond asMicroSeconds. + self assert: 1 equals: 1 microSecond asMicroSeconds. + self assert: -1 equals: -1 microSecond asMicroSeconds. + self assert: 0 equals: 0 microSecond asMicroSeconds. + self assert: 1500 equals: 1.5 microSecond asNanoSeconds. + self assert: -1500 equals: -1.5 microSecond asNanoSeconds. + ! Item was added: + ----- Method: DurationTest>>testMilliSecondsFromNumber (in category 'tests - from number') ----- + testMilliSecondsFromNumber + + self assert: 5 equals: 5 milliSeconds asMilliSeconds. + self assert: -5 equals: -5 milliSeconds asMilliSeconds. + self assert: 1 equals: 1 milliSeconds asMilliSeconds. + self assert: -1 equals: -1 milliSeconds asMilliSeconds. + self assert: 0 equals: 0 milliSeconds asMilliSeconds. + self assert: 1500 equals: 1.5 milliSeconds asMicroSeconds. + self assert: -1500 equals: -1.5 milliSeconds asMicroSeconds. + + self assert: 5 equals: 5 milliSecond asMilliSeconds. + self assert: -5 equals: -5 milliSecond asMilliSeconds. + self assert: 1 equals: 1 milliSecond asMilliSeconds. + self assert: -1 equals: -1 milliSecond asMilliSeconds. + self assert: 0 equals: 0 milliSecond asMilliSeconds. + self assert: 1500 equals: 1.5 milliSecond asMicroSeconds. + self assert: -1500 equals: -1.5 milliSecond asMicroSeconds. + ! Item was added: + ----- Method: DurationTest>>testMinutesFromNumber (in category 'tests - from number') ----- + testMinutesFromNumber + + self assert: 5 equals: 5 minutes asSeconds / 60. + self assert: -5 equals: -5 minutes asSeconds / 60. + self assert: 1 equals: 1 minutes asSeconds / 60. + self assert: -1 equals: -1 minutes asSeconds / 60. + self assert: 0 equals: 0 minutes asSeconds / 60. + self assert: 1500 equals: 1.5 minutes asMilliSeconds / 60. + self assert: -1500 equals: -1.5 minutes asMilliSeconds / 60. + + self assert: 5 equals: 5 minute asSeconds / 60. + self assert: -5 equals: -5 minute asSeconds / 60. + self assert: 1 equals: 1 minute asSeconds / 60. + self assert: -1 equals: -1 minute asSeconds / 60. + self assert: 0 equals: 0 minute asSeconds / 60. + self assert: 1500 equals: 1.5 minute asMilliSeconds / 60. + self assert: -1500 equals: -1.5 minute asMilliSeconds / 60. + ! Item was added: + ----- Method: DurationTest>>testNanoSecondsFromNumber (in category 'tests - from number') ----- + testNanoSecondsFromNumber + + self assert: 5 equals: 5 nanoSeconds asNanoSeconds. + self assert: -5 equals: -5 nanoSeconds asNanoSeconds. + self assert: 1 equals: 1 nanoSeconds asNanoSeconds. + self assert: -1 equals: -1 nanoSeconds asNanoSeconds. + self assert: 0 equals: 0 nanoSeconds asNanoSeconds. + + self assert: 5 equals: 5 nanoSecond asNanoSeconds. + self assert: -5 equals: -5 nanoSecond asNanoSeconds. + self assert: 1 equals: 1 nanoSecond asNanoSeconds. + self assert: -1 equals: -1 nanoSecond asNanoSeconds. + self assert: 0 equals: 0 nanoSecond asNanoSeconds. + ! Item was added: + ----- Method: DurationTest>>testSecondsFromNumber (in category 'tests - from number') ----- + testSecondsFromNumber + + self assert: 5 equals: 5 seconds asSeconds. + self assert: -5 equals: -5 seconds asSeconds. + self assert: 1 equals: 1 seconds asSeconds. + self assert: -1 equals: -1 seconds asSeconds. + self assert: 0 equals: 0 seconds asSeconds. + self assert: 1500 equals: 1.5 seconds asMilliSeconds. + self assert: -1500 equals: -1.5 seconds asMilliSeconds. + + self assert: 5 equals: 5 second asSeconds. + self assert: -5 equals: -5 second asSeconds. + self assert: 1 equals: 1 second asSeconds. + self assert: -1 equals: -1 second asSeconds. + self assert: 0 equals: 0 second asSeconds. + self assert: 1500 equals: 1.5 second asMilliSeconds. + self assert: -1500 equals: -1.5 second asMilliSeconds. + ! Item was added: + ----- Method: DurationTest>>testWeeksFromNumber (in category 'tests - from number') ----- + testWeeksFromNumber + + self assert: 5 equals: 5 weeks asSeconds / 604800. + self assert: -5 equals: -5 weeks asSeconds / 604800. + self assert: 1 equals: 1 weeks asSeconds / 604800. + self assert: -1 equals: -1 weeks asSeconds / 604800. + self assert: 0 equals: 0 weeks asSeconds / 604800. + self assert: 1500 equals: 1.5 weeks asMilliSeconds / 604800. + self assert: -1500 equals: -1.5 weeks asMilliSeconds / 604800. + + self assert: 5 equals: 5 week asSeconds / 604800. + self assert: -5 equals: -5 week asSeconds / 604800. + self assert: 1 equals: 1 week asSeconds / 604800. + self assert: -1 equals: -1 week asSeconds / 604800. + self assert: 0 equals: 0 week asSeconds / 604800. + self assert: 1500 equals: 1.5 week asMilliSeconds / 604800. + self assert: -1500 equals: -1.5 week asMilliSeconds / 604800. + ! From commits at source.squeak.org Tue Mar 30 19:39:47 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Tue, 30 Mar 2021 19:39:47 0000 Subject: [squeak-dev] The Trunk: Chronology-Core-dtl.66.mcz Message-ID: David T. Lewis uploaded a new version of Chronology-Core to project The Trunk: http://source.squeak.org/trunk/Chronology-Core-dtl.66.mcz ==================== Summary ==================== Name: Chronology-Core-dtl.66 Author: dtl Time: 28 March 2021, 10:52:56.0001 am UUID: 9695afba-0eaf-49ab-8d2e-177f089f1d04 Ancestors: Chronology-Core-dtl.65 Let "1 second" be a synonym for "1 seconds" so that "5 second" does not answer one second. Likewise for minute, hour, etc. =============== Diff against Chronology-Core-dtl.65 =============== Item was changed: ----- Method: Number>>day (in category '*chronology-core') ----- day + ^ self days! - ^ self sign days! Item was changed: ----- Method: Number>>hour (in category '*chronology-core') ----- hour + ^ self hours - ^ self sign hours ! Item was changed: ----- Method: Number>>microSecond (in category '*chronology-core') ----- microSecond + ^ self microSeconds! - ^ self sign microSeconds! Item was changed: ----- Method: Number>>milliSecond (in category '*chronology-core') ----- milliSecond + ^ self milliSeconds - ^ self sign milliSeconds ! Item was changed: ----- Method: Number>>minute (in category '*chronology-core') ----- minute + ^ self minutes - ^ self sign minutes ! Item was changed: ----- Method: Number>>nanoSecond (in category '*chronology-core') ----- nanoSecond + ^ self nanoSeconds - ^ self sign nanoSeconds ! Item was changed: ----- Method: Number>>second (in category '*chronology-core') ----- second + ^ self seconds - ^ self sign seconds ! Item was changed: ----- Method: Number>>week (in category '*chronology-core') ----- week + ^ self weeks - ^ self sign weeks ! From leves at caesar.elte.hu Tue Mar 30 20:05:02 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Tue, 30 Mar 2021 22:05:02 +0200 (CEST) Subject: [squeak-dev] Stream nextPutAll: with an OrderedCollection go boom In-Reply-To: <28F42B3A-7A23-4DF3-82E6-A092B859486B@rowledge.org> References: <28F42B3A-7A23-4DF3-82E6-A092B859486B@rowledge.org> Message-ID: Hi Tim, On Tue, 30 Mar 2021, tim Rowledge wrote: > I spotted a previous mention of this in the old maillist archives but it is still a current failure - > > (OrderedCollection > streamContents: > [:strm | > strm > nextPutAll: (OrderedCollection with: 1 ) ]) > > Boom! I still agree with my previous answers[1]: don't do that. Just use OrderedCollection's own API if you want to build a collection. > > It's fine if we add asArray > > I'm suspicious of WriteStream>>#nextPutAll: making the assumption that SequenceableCollection>>#replaceFrom:to:with:startingAt: is always ok. Clearly not for OrderedCollection... > > Looks to me that we need to make OrderedCollection not pass the check for the 'fast path'? How about changing the #isBits test for a more capability oriented #canAcceptFastPathNextPut ? There's no need to change anything there to support a bad pattern. If you really-really want to make it work, just override #new:streamContents:: OrderedCollection class >> new: newSize streamContents: blockWithArg | contents | contents := self arrayType new: newSize streamContents: blockWithArg. ^self basicNew setContents: contents; yourself Levente [1] http://forum.world.st/streamContents-on-OrderedCollection-broken-td4760369.html > > tim > -- > tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim > A bug in the code is worth two in the documentation. From leves at caesar.elte.hu Tue Mar 30 20:10:22 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Tue, 30 Mar 2021 22:10:22 +0200 (CEST) Subject: [squeak-dev] The Inbox: Chronology-Core-dtl.66.mcz In-Reply-To: <20210328185556.GA75142@shell.msen.com> References: <1616948017696-0.post@n4.nabble.com> <20210328185556.GA75142@shell.msen.com> Message-ID: Hi David, On Sun, 28 Mar 2021, David T. Lewis wrote: > On Sun, Mar 28, 2021 at 11:13:37AM -0500, Jaromir Matas wrote: >> Hi, >> great! >> >> Would it be a bad idea to have milliseconds instead (or on top) of >> milliSeconds? Etc. >> > > I would not want to bother with that. It would just add more stuff > to the API, and the existing selector names are good enough. I find the existing names annoying. I think the author of those methods was not familiar with the SI system. Levente > > Dave From leves at caesar.elte.hu Tue Mar 30 20:21:00 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Tue, 30 Mar 2021 22:21:00 +0200 (CEST) Subject: [squeak-dev] Extending the functionality of caseOf: (was: #identityCaseOf:) In-Reply-To: References: <20210328202253.GA99661@shell.msen.com> Message-ID: Hi Chris, On Sun, 28 Mar 2021, Chris Muller wrote: > > For example, passing the object to the condition block (or even the result > > block) could be useful: > > > > self someComplexExpression caseOf: { > >       [ 1 ] -> [ self success ] > >       [ :value | value odd ] -> [ :value | self processEvenValue: value - > >       1 ]. > >       [ :value | true "it's even ] -> [ :value | self processEvenValue ] }  > > > > > There are two new things in the example: > > - the value of self someComplexExpression is optionally passed to the > > blocks. Yes, that could be done by creating a temporary variable. > > > Here's the version using a temporary and existing API (with an added identity-check). > >    result := self someComplexExpression. >    true caseOf: >       { [result=1] -> [self success]. >       [result odd] -> [self processEvenValue: result-1]. >       [ result == identityValue ] -> [self processSomethingElse ]. >       [true] -> [self processEvenValue] } > > "true caseOf:" is my sneaky way to improve its flexibility.  The suggested expansion of the API seems too dilute, not enough bang. Yes, it does the job, but it's a bit more verbose and probably less efficient: you have to declare the variable yourself, and you have to write result=1 instead of just 1. >   > The > > compiler could do exactly that behind the scenes. > > - when the value is passed to the matcher block, possibilities are greatly > > extended. > > > The evaluation is done before any of the caseOf tests, so is it really extended with more expressive power?  Or just a different syntax that moves the variable declaration from a temporary to the block arg? It's just syntactic sugar. The optimized evaluation would just reuse the existing temporary instead of creating a new one all the time. The default implementation would be Object >> caseOf: aBlockAssociationCollection otherwise: aBlock aBlockAssociationCollection associationsDo: [:assoc | (assoc key numArgs = 0 ifTrue: [ assoc key value = self ] ifFalse: [ assoc key value: self ]) ifTrue: [^assoc value cull: self]]. ^ aBlock cull: self Levente >   > For example, it could even reproduce #identityCaseOf: > > > >       foo caseOf: { > >               [ :o | o == #foo ] -> [ self foo ]. > >               [ :o | o == #bar ] -> [ self bar ] } > > > > The same thing could be done with the otherwise block too: > > > >       self foo > >               caseOf: { ... } > >               otherwise: [ :value | value ] > > > > > > Levente > > > > > > From lewis at mail.msen.com Tue Mar 30 20:21:28 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Tue, 30 Mar 2021 16:21:28 -0400 Subject: [squeak-dev] The Inbox: Chronology-Core-dtl.66.mcz In-Reply-To: References: <1616948017696-0.post@n4.nabble.com> <20210328185556.GA75142@shell.msen.com> Message-ID: <20210330202128.GA24434@shell.msen.com> On Tue, Mar 30, 2021 at 10:10:22PM +0200, Levente Uzonyi wrote: > Hi David, > > On Sun, 28 Mar 2021, David T. Lewis wrote: > > >On Sun, Mar 28, 2021 at 11:13:37AM -0500, Jaromir Matas wrote: > >>Hi, > >>great! > >> > >>Would it be a bad idea to have milliseconds instead (or on top) of > >>milliSeconds? Etc. > >> > > > >I would not want to bother with that. It would just add more stuff > >to the API, and the existing selector names are good enough. > > I find the existing names annoying. I think the author of those > methods was not familiar with the SI system. > I have no strong opinion one way or the other. It's a bit of aggrivation to manage the deprecation process, but aside from that I guess there is no reason not to fix the selector names. Should we do that? Dave From tim at rowledge.org Tue Mar 30 21:31:41 2021 From: tim at rowledge.org (tim Rowledge) Date: Tue, 30 Mar 2021 14:31:41 -0700 Subject: [squeak-dev] Stream nextPutAll: with an OrderedCollection go boom In-Reply-To: References: <28F42B3A-7A23-4DF3-82E6-A092B859486B@rowledge.org> Message-ID: <57B3EB32-6B51-428C-8681-BB646199DA38@rowledge.org> > On 2021-03-30, at 1:05 PM, Levente Uzonyi wrote: > > I still agree with my previous answers[1]: don't do that. Just use OrderedCollection's own API if you want to build a collection. Well, yeah, but. I like things to be decently uniform and at least try to meet the implicit contract. In this case the problem is purely because the test to do a 'fast hack' wrongly passes. tim -- tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim Security announcement - as of next week, passwords will be entered in Morse code. From lewis at mail.msen.com Wed Mar 31 00:10:22 2021 From: lewis at mail.msen.com (David T. Lewis) Date: Tue, 30 Mar 2021 20:10:22 -0400 Subject: [squeak-dev] Stream nextPutAll: with an OrderedCollection go boom In-Reply-To: <57B3EB32-6B51-428C-8681-BB646199DA38@rowledge.org> References: <28F42B3A-7A23-4DF3-82E6-A092B859486B@rowledge.org> <57B3EB32-6B51-428C-8681-BB646199DA38@rowledge.org> Message-ID: <20210331001022.GA47499@shell.msen.com> On Tue, Mar 30, 2021 at 02:31:41PM -0700, tim Rowledge wrote: > > > > On 2021-03-30, at 1:05 PM, Levente Uzonyi wrote: > > > > I still agree with my previous answers[1]: don't do that. Just use OrderedCollection's own API if you want to build a collection. > > Well, yeah, but. > > I like things to be decently uniform and at least try to meet the implicit contract. In this case the problem is purely because the test to do a 'fast hack' wrongly passes. > Trying to follow the discussion. Where is the "test to do a 'fast hack'" that wrongly passes? Dave From commits at source.squeak.org Wed Mar 31 00:18:41 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 31 Mar 2021 00:18:41 0000 Subject: [squeak-dev] The Trunk: Collections-ul.932.mcz Message-ID: Levente Uzonyi uploaded a new version of Collections to project The Trunk: http://source.squeak.org/trunk/Collections-ul.932.mcz ==================== Summary ==================== Name: Collections-ul.932 Author: ul Time: 31 March 2021, 2:12:26.200489 am UUID: a61726a6-a12e-4074-a25f-8220699d3c06 Ancestors: Collections-dtl.931 - use #grownBy: in WriteStream >> #growTo: to grow the collection because that works for OrderedCollections too. - do not add 10 to the argument passed to WriteStream >> #growTo:. It will already increase its argument by at least 20. =============== Diff against Collections-dtl.931 =============== Item was changed: ----- Method: LimitedWriteStream>>nextPutAll: (in category 'writing') ----- nextPutAll: aCollection | newEnd | collection class == aCollection class ifFalse: [^ super nextPutAll: aCollection ]. newEnd := position + aCollection size. newEnd > limit ifTrue: [ super nextPutAll: (aCollection copyFrom: 1 to: (limit - position max: 0)). limitBlock value. ^aCollection ]. newEnd > writeLimit ifTrue: [ + self growTo: newEnd - self growTo: newEnd + 10 ]. collection replaceFrom: position+1 to: newEnd with: aCollection startingAt: 1. position := newEnd. ^aCollection! Item was changed: ----- Method: TextStream>>nextPutAll: (in category 'writing') ----- nextPutAll: aCollection "Optimized access to get around Text at:Put: overhead" | n | n := aCollection size. position + n > writeLimit ifTrue: + [self growTo: position + n]. - [self growTo: position + n + 10]. collection replaceFrom: position+1 to: position + n with: aCollection startingAt: 1. position := position + n. ^aCollection! Item was changed: ----- Method: WriteStream>><< (in category 'printing') ----- << aCollection "we want a readable version of nextPutAll however it may be difficult to fully recreate nextPutAll: for all the different types of stream. Rather then simply send to nextPutAll: we handle the String (or ByteArray) argument as fast as possible - the rest we delegate to putOn: This means that we handle single characters and bytes whereas nextPutAll: is only for sequencable collections. . Note this may not work in every case that nextPutAll: does subject to extensive testing, but it should work in the important cases" | newEnd | collection class == aCollection class ifFalse: [ aCollection putOn: self. ^ self ]. newEnd := position + aCollection size. newEnd > writeLimit ifTrue: + [self growTo: newEnd]. - [self growTo: newEnd + 10]. collection replaceFrom: position+1 to: newEnd with: aCollection startingAt: 1. position := newEnd. ! Item was changed: ----- Method: WriteStream>>growTo: (in category 'private') ----- growTo: anInteger + " anInteger is the required minimal new size of the collection " + | oldSize newSize | - " anInteger is the required minimal new size of the collection " - | oldSize grownCollection newSize | oldSize := collection size. + newSize := anInteger + (oldSize // 4 max: 20). + collection := collection grownBy: newSize - oldSize. - newSize := anInteger + (oldSize // 4 max: 20). - grownCollection := collection class new: newSize. - collection := grownCollection replaceFrom: 1 to: oldSize with: collection startingAt: 1. writeLimit := collection size. ! Item was changed: ----- Method: WriteStream>>next:putAll:startingAt: (in category 'accessing') ----- next: anInteger putAll: aCollection startingAt: startIndex "Store the next anInteger elements from the given collection." | newEnd | anInteger > 0 ifFalse: [ ^aCollection ]. (collection class == aCollection class or: [ collection isString and: [ aCollection isString and: [ collection class format = aCollection class format ] ] ]) "Let Strings with the same field size as collection take the quick route too." ifFalse: [ ^super next: anInteger putAll: aCollection startingAt: startIndex ]. newEnd := position + anInteger. newEnd > writeLimit ifTrue: + [self growTo: newEnd]. - [self growTo: newEnd + 10]. collection replaceFrom: position+1 to: newEnd with: aCollection startingAt: startIndex. position := newEnd. ^aCollection! Item was changed: ----- Method: WriteStream>>nextPutAll: (in category 'accessing') ----- nextPutAll: aCollection | newEnd | (collection class == aCollection class or: [ collection class isBits and: [ aCollection isString and: [ collection class format = aCollection class format ] ] ]) "Let Strings with the same field size as collection take the quick route too." ifFalse: [ ^ super nextPutAll: aCollection ]. newEnd := position + aCollection size. newEnd > writeLimit ifTrue: + [self growTo: newEnd]. - [self growTo: newEnd + 10]. collection replaceFrom: position+1 to: newEnd with: aCollection startingAt: 1. position := newEnd. ^aCollection! From commits at source.squeak.org Wed Mar 31 00:18:58 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 31 Mar 2021 00:18:58 0000 Subject: [squeak-dev] The Inbox: Collections-ul.933.mcz Message-ID: Levente Uzonyi uploaded a new version of Collections to project The Inbox: http://source.squeak.org/inbox/Collections-ul.933.mcz ==================== Summary ==================== Name: Collections-ul.933 Author: ul Time: 31 March 2021, 2:17:52.141067 am UUID: b290ad2c-2ed0-4d46-b2fe-12545bf5f31c Ancestors: Collections-ul.932 - use #ofSize: instead of #new: in SequenceableCollection class >> new:streamContents:, so that it creates a stream on a non-empty collection even if the receiver is OrderedCollection. =============== Diff against Collections-ul.932 =============== Item was changed: ----- Method: SequenceableCollection class>>new:streamContents: (in category 'stream creation') ----- new: newSize streamContents: blockWithArg | stream originalContents | + stream := WriteStream on: (self ofSize: newSize). - stream := WriteStream on: (self new: newSize). blockWithArg value: stream. originalContents := stream originalContents. + ^originalContents size = stream position + ifTrue: [ originalContents ] + ifFalse: [ stream contents ]! - originalContents size = stream position - ifTrue: [ ^originalContents ] - ifFalse: [ ^stream contents ]! From leves at caesar.elte.hu Wed Mar 31 00:23:25 2021 From: leves at caesar.elte.hu (Levente Uzonyi) Date: Wed, 31 Mar 2021 02:23:25 +0200 (CEST) Subject: [squeak-dev] Stream nextPutAll: with an OrderedCollection go boom In-Reply-To: <57B3EB32-6B51-428C-8681-BB646199DA38@rowledge.org> References: <28F42B3A-7A23-4DF3-82E6-A092B859486B@rowledge.org> <57B3EB32-6B51-428C-8681-BB646199DA38@rowledge.org> Message-ID: On Tue, 30 Mar 2021, tim Rowledge wrote: > > >> On 2021-03-30, at 1:05 PM, Levente Uzonyi wrote: >> >> I still agree with my previous answers[1]: don't do that. Just use OrderedCollection's own API if you want to build a collection. > > Well, yeah, but. > > I like things to be decently uniform and at least try to meet the implicit contract. In this case the problem is purely because the test to do a 'fast hack' wrongly passes. No, that's not the problem. The problem is that OrderedCollection >> #new: returns a collection that is always empty. When WriteStream >> #nextPutAll: sees the empty collection, it tries to make enough room for the elements to be added by sending #growTo: to itself. #growTo: sends #new: to the collection's class, which in case of OrderedCollection will return another empty collection. So, collection will remain empty after #growTo:. #nextPutAll: rightfully assumes that now there is enough space for the elements to be added, but there's still none, hence the error. The real solution is to change WriteStream >> #growTo: to WriteStream >> growTo: anInteger " anInteger is the required minimal new size of the collection " | oldSize newSize | oldSize := collection size. newSize := anInteger + (oldSize // 4 max: 20). collection := collection grownBy: newSize - oldSize. writeLimit := collection size. It has 5 senders in the WriteStream hierarchy in my image. All of those unnecessarily add 10 to the requested new size, even through #growTo: will add at least 20 extra slots. Collections-ul.932 fixes that. There's also Collections-ul.933 in the Inbox which slightly improves the performance of OrderedCollection streamContents: by avoiding allocating an empty initial collection. If you find that useful, push it to the Trunk. But even with that fix, there will be several subclasses of SequenceableCollection which won't work with WriteStreams and #streamContents:. Levente > > tim > -- > tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim > Security announcement - as of next week, passwords will be entered in Morse code. From m at jaromir.net Wed Mar 31 09:16:47 2021 From: m at jaromir.net (Jaromir Matas) Date: Wed, 31 Mar 2021 04:16:47 -0500 (CDT) Subject: [squeak-dev] Another bug in Process>>#terminate in unwinding contexts ? Message-ID: <1617182207794-0.post@n4.nabble.com> Hi, if you examine the following example you'll notice only the innermost unwind context currently under evaluation will get completed during termination. But the unwind contexts may be nested so I guess we should attempt completing the outermost context rather than the innermost only. | p | p := [ [ ] ensure: [ [ ] ensure: [Processor activeProcess suspend. Transcript show: 'x1']. Transcript show: 'x2'] ] fork. Processor yield. p terminate Expected output: x1 x2 Real output: x1 (`Processor activeProcess suspend` models a situation a process gets suspended and then for whatever reason terminated) This is the current implementation within #teminate: "If terminating a process halfways through an unwind, try to complete that unwind block first." (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: [:outer| (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: [:inner| "This is an unwind block currently under evaluation" suspendedContext runUntilErrorOrReturnFrom: inner]]. I'm proposing this modification: "If terminating a process halfways through an unwind, try to complete that unwind block first." ctxt := suspendedContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [outerMost := ctxt]. outerMost ifNotNil: ["This is the bottom-most unwind context currently under evaluation; now let's find the currently context executing its argument block (tempAt: 1)" (suspendedContext findContextSuchThat: [:c | c closure == (outerMost tempAt: 1)]) ifNotNil: [:inner | suspendedContext runUntilErrorOrReturnFrom: inner]]. Changeset: Process-terminate_modify_outerMost.st Other bugs in terminate (and related): [1] http://forum.world.st/Bug-in-Process-gt-gt-terminate-Returning-from-unwind-contexts-td5127570.html [2] http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html#a5127372 [3] http://forum.world.st/Refactoring-terminate-to-get-rid-of-cannot-return-errors-etc-td5127732.html (The last is a part of my effort to refactor termination to at least deal with the current bugs) ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From m at jaromir.net Wed Mar 31 17:58:01 2021 From: m at jaromir.net (Jaromir Matas) Date: Wed, 31 Mar 2021 12:58:01 -0500 (CDT) Subject: [squeak-dev] Another bug in Process>>#terminate in unwinding contexts ? In-Reply-To: <1617182207794-0.post@n4.nabble.com> References: <1617182207794-0.post@n4.nabble.com> Message-ID: <1617213481208-0.post@n4.nabble.com> Unfortunately there's one more bug in #terminate: The existing code fails to execute unwind blocks after completing the innermost unwind block. Examine the following example nesting two unwind blocks halfway through execution and one outer unwind block not started yet: | p | p := [ [ [ ] ensure: ["x2" [ ] ensure: ["x1" Processor activeProcess suspend. Transcript show: 'x1']. Transcript show: 'x2'] ] ensure: ["x3" Transcript show: 'x3'] ] fork. Processor yield. p terminate ---> x1 (only!) Process p is suspended halfway through an unwind block x1 and is terminated - you'd expect #terminate to finish the unfinished unwind blocks x1 and x2 and execute an outer unwind block x3. But the result is only x1 is completed and both x2 and x3 are ignored! The reason x3 is ignored is that #runUntilErrorOrReturnFrom: resets suspendedContext sender to nil so the rest of the code is doing nothing useful. The fix is to update suspendedContext after #runUntilErrorOrReturnFrom is returned from. Process >> terminate "..." ctxt := suspendedContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt:2) ifNotNil: [outerMost := ctxt]]. outerMost ifNotNil: ["This is the bottom-most unwind context currently under evaluation; now let's find the currently context executing its argument block (tempAt: 1)" (suspendedContext findContextSuchThat: [:c | c closure == (outerMost tempAt: 1)]) ifNotNil: [:inner | suspendedContext runUntilErrorOrReturnFrom: inner. "update suspendedContext" suspendedContext := outerMost]]. "..." Now the test example returns 'x1 x2 x3' as expected. Updated changeset enclosed: Process-terminate_modify_outerMost_v2.st Thanks for your comments. ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html From commits at source.squeak.org Wed Mar 31 21:11:55 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 31 Mar 2021 21:11:55 0000 Subject: [squeak-dev] The Inbox: Kernel-jar.1384.mcz Message-ID: A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-jar.1384.mcz ==================== Summary ==================== Name: Kernel-jar.1384 Author: jar Time: 31 March 2021, 11:11:51.005212 pm UUID: 7fa9b545-e341-054f-835a-c1bd059fd414 Ancestors: Kernel-mt.1383 Fixes current implementation ignoring some nested unwind blocks in common situations. Explained and documented in http://forum.world.st/Another-bug-in-Process-terminate-in-unwinding-contexts-tp5128171p5128178.html A test follows. =============== Diff against Kernel-mt.1383 =============== Item was changed: ----- Method: Process>>terminate (in category 'changing process state') ----- terminate "Stop the process that the receiver represents forever. Unwind to execute pending ensure:/ifCurtailed: blocks before terminating. If the process is in the middle of a critical: critical section, release it properly." + | ctxt unwindBlock oldList outerMost | - | ctxt unwindBlock oldList | self isActiveProcess ifTrue: [ctxt := thisContext. [ctxt := ctxt findNextUnwindContextUpTo: nil. ctxt ~~ nil] whileTrue: [(ctxt tempAt: 2) ifNil: ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true." unwindBlock := ctxt tempAt: 1. thisContext terminateTo: ctxt. unwindBlock value]]. thisContext terminateTo: nil. self suspend. "If the process is resumed this will provoke a cannotReturn: error. Would self debug: thisContext title: 'Resuming a terminated process' be better?" ^self]. "Always suspend the process first so it doesn't accidentally get woken up. N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al then the process is blocked, and if it is nil then the process is already suspended." oldList := self suspend. suspendedContext ifNotNil: ["Release any method marked with the pragma. The argument is whether the process is runnable." self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]). + "If terminating a process halfways through an unwind, try to complete that unwind block first; + if there are multiple such nested unwind blocks, try to complete the outer-most block + (i.e. the one closest to the bottom of the stack)" + ctxt := suspendedContext. + [(ctxt := ctxt findNextUnwindContextUpTo: nil) isNil] whileFalse: + "contexts under evaluation have already set their complete (tempAt: 2) to true" + [(ctxt tempAt:2) ifNotNil: [outerMost := ctxt]]. + outerMost ifNotNil: [ + "This is the outer-most unwind context currently under evaluation; + let's find an inner context executing outerMost's argument block (tempAt: 1)" + (suspendedContext findContextSuchThat: [:ctx | + ctx closure == (outerMost tempAt: 1)]) ifNotNil: [:inner | + suspendedContext runUntilErrorOrReturnFrom: inner. + "update receiver's suspendedContext reset in the previous step" + suspendedContext := outerMost]]. - "If terminating a process halfways through an unwind, try to complete that unwind block first." - (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil: - [:outer| - (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil: - [:inner| "This is an unwind block currently under evaluation" - suspendedContext runUntilErrorOrReturnFrom: inner]]. ctxt := self popTo: suspendedContext bottomContext. ctxt == suspendedContext bottomContext ifFalse: [self debugWithTitle: 'Unwind error during termination' translated full: false]. "Set the context to its endPC for the benefit of isTerminated." ctxt pc: ctxt endPC]! From commits at source.squeak.org Wed Mar 31 21:14:33 2021 From: commits at source.squeak.org (commits at source.squeak.org) Date: Wed, 31 Mar 2021 21:14:33 0000 Subject: [squeak-dev] The Inbox: KernelTests-jar.395.mcz Message-ID: A new version of KernelTests was added to project The Inbox: http://source.squeak.org/inbox/KernelTests-jar.395.mcz ==================== Summary ==================== Name: KernelTests-jar.395 Author: jar Time: 31 March 2021, 11:14:30.909212 pm UUID: b63793d5-9635-c942-a9c5-132e788a8eda Ancestors: KernelTests-mt.394 complementing Kernel-jar.1384 (The Inbox) =============== Diff against KernelTests-mt.394 =============== Item was added: + ----- Method: ProcessTest>>testNestedUnwind (in category 'tests') ----- + testNestedUnwind + "Test all nested unwind blocks are correctly unwound; all unwind blocks halfway through their execution should be completed or at least attempted to complete, not only the innermost one" + + | p x1 x2 x3 | + x1 := x2 := x3 := false. + p := + [ + [ + [ ] ensure: [ "halfway through completion when suspended" + [ ] ensure: [ "halfway through completion when suspended" + Processor activeProcess suspend. + x1 := true]. + x2 := true] + ] ensure: [ "not started yet when suspended" + x3 := true] + ] fork. + Processor yield. + p terminate. + + self assert: x1 & x2 & x3!