<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
</head>
<body>
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p>Hi Marcel,</p>
<p><br>
</p>
<p>it's already reverted via <span>Collections-ct.972. I absolutely agree with discussing ideas like this properly before adding them to the Trunk. Maybe we can still address the points from my previous questions, maybe after the release. :-)</span></p>
<p><span><br>
</span></p>
<p><span>Best,</span></p>
<p><span>Christoph</span></p>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>Von:</b> Squeak-dev <squeak-dev-bounces@lists.squeakfoundation.org> im Auftrag von Taeumel, Marcel<br>
<b>Gesendet:</b> Mittwoch, 29. Dezember 2021 07:13:09<br>
<b>An:</b> squeak-dev<br>
<b>Betreff:</b> Re: [squeak-dev] The Trunk: Collections-ct.972.mcz</font>
<div> </div>
</div>
<div>
<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
Hi Christoph --
<div><br>
</div>
<div>-1 Please remove this again. Such a new data structure needs time to be discussed and tested. It's way too late in the release process to add something like this.</div>
<div><br>
</div>
<div>Best,</div>
<div>Marcel</div>
<div class="mb_sig"></div>
<blockquote class="history_container" type="cite" style="border-left-style:solid;border-width:1px; margin-top:20px; margin-left:0px;padding-left:10px;">
<p style="color: #AAAAAA; margin-top: 10px;">Am 29.12.2021 03:49:11 schrieb Thiede, Christoph <christoph.thiede@student.hpi.uni-potsdam.de>:</p>
<div style="font-family:Arial,Helvetica,sans-serif">
<div id="divtagdefaultwrapper" style="font-size: 12pt;color: #000000;font-family: Calibri,Helvetica,sans-serif" dir="ltr">
<p><span style="font-size: 12pt">Thank you for the very helpful critique, Dave! I have removed </span><span style="font-size: 12pt">PluggableWeakKeyDictionary from the Collections package again. When I come up with another idea of this extent, I will upload
 it to the inbox only, I promise. :-)</span><br>
</p>
<div dir="ltr">
<div id="x_divtagdefaultwrapper" dir="ltr" style="font-size: 12pt;color: rgb(0, 0, 0);font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols">
<p><span><br>
</span></p>
<p><span>For further potential extensions to Collections and other packages, we should maybe document an answer to these questions:</span></p>
<p><span>Do protocols such as the Collection hierarchy function as an internal support package for other Trunk packages only, or do they also address external client packages? Until today, I have always assumed the latter and thought of the Collections package
 as a public API.</span></p>
<p><span>Is a protocol only useful and legitimate if it is used in the Trunk? As an example, <span>WeakKeyDictionary has no senders in the Trunk, too, but I see a two-digit
<a href="https://sourcegraph.com/search?q=context:global+WeakKeyDictionary+lang:Smalltalk+-lang:c%23&patternType=literal" class="OWAAutoLink">
number</a> of dependent packages only on GitHub and most of these users appear legitimate to me. Other examples include resumable test failures, traits, and promises - to me, all of them appear to be valid and useful concepts. They may appear as dead concepts
 in a plain Trunk image, but there are enough external packages and projects making real use of them. Maintenance and discoverability are nevertheless two very important aspects, of course.</span></span></p>
<p><span><span><br>
</span></span></p>
<p><span><span>Personally, I can still think of valid use cases for a <span>PluggableWeakKeyDictionary (at least outside of the Trunk - see my previous post for details), and I am open to better implementation strategies. But this decision depends on the majority
 of voices. I'm looking forward to an interesting discussion. :-)</span></span></span></p>
<p><span><span><span><br>
</span></span></span></p>
<p><span><span><span>Best,</span></span></span></p>
<p><span><span><span>Christoph</span></span></span></p>
<p><span><br>
</span></p>
</div>
<hr style="display:inline-block; width:98%" tabindex="-1">
<div id="x_divRplyFwdMsg" dir="ltr"><span style="font-family: Calibri, sans-serif;color: #000000"><b>Von:</b> Squeak-dev <squeak-dev-bounces@lists.squeakfoundation.org> im Auftrag von David T. Lewis <lewis@mail.msen.com><br>
<b>Gesendet:</b> Mittwoch, 29. Dezember 2021 00:11:49<br>
<b>An:</b> The general-purpose Squeak developers list<br>
<b>Betreff:</b> Re: [squeak-dev] The Trunk: Collections-ct.972.mcz</span>
<div> </div>
</div>
</div>
<span style="font-size: 10pt"><span style="font-size: 10pt">
<div class="PlainText">I would advise against including PluggableWeakKeyDictionary in trunk<br>
at the present time. It can be added later if the need arises.<br>
<br>
Why?<br>
<br>
1) Cognitive clutter. Adding things that are not actually necessary<br>
means that the reader has more to understand when looking at the<br>
Dictionary hierarchy.<br>
<br>
2) Refactorability. If in the future someone wants to make pluggable-ness<br>
more general for some reason, then having it present in two places<br>
in the Dictionary hierarchy makes the job more difficult.<br>
<br>
3) Housekeeping. It is easy to add something to the image, but<br>
very difficult to make it go away. Imagine that someone five years<br>
from now wants to deprecate PluggableWeakKeyDictionary, perhaps<br>
just because it is not used, or maybe because they have a better<br>
refactoring in mind. Once it is in trunk, you can never be certain<br>
that it is not referenced by some external package, so things<br>
like this tend to stay around for a long time even if they serve<br>
no purpose.<br>
<br>
Dave<br>
<br>
<br>
On Mon, Dec 27, 2021 at 07:36:16PM +0000, Thiede, Christoph wrote:<br>
> Hi Levente,<br>
> <br>
> <br>
> two goals: First of all, I was assuming that we aim to provide a comprehensive set of features in the Collections package, and having no possibility to customize the key comparison in weak key dictionaries sounded like a logical gap to me. There are no senders
 of WeakKeyDictionary in the Trunk but it IMO still adds value to the package. Second, I am actually having a use case for PluggableWeakKeyDictionary in a third-party package (SimulationStudio#34<https://github.com/LinqLover/SimulationStudio/pull/34/files/3137fe3772b288654d377fc9470302ab2fd26148>)
 where I need to compare keys by mirror primitives but still need to hold them weakly.<br>
> <br>
> <br>
> I have uploaded this class directly to Trunk because I could not see any harm in it and did not want to create another helper package for Collections. If there was anything wrong with this approach, I apologize and we can remove this class immediately again.
 Still, I would find a PluggableWeakKeyDictionary in the Trunk useful.<br>
> <br>
> <br>
> > And I think there might be a better way to do what you want to achieve than copying all those methods.<br>
> <br>
> <br>
> What approach were you having in mind concretely? :-)<br>
> <br>
> <br>
> Best,<br>
> <br>
> Christoph<br>
> <br>
> ________________________________<br>
> Von: Squeak-dev <squeak-dev-bounces@lists.squeakfoundation.org> im Auftrag von Levente Uzonyi <leves@caesar.elte.hu><br>
> Gesendet: Montag, 27. Dezember 2021 18:35:12<br>
> An: squeak-dev@lists.squeakfoundation.org<br>
> Cc: packages@lists.squeakfoundation.org<br>
> Betreff: Re: [squeak-dev] The Trunk: Collections-ct.972.mcz<br>
> <br>
> Hi Christoph,<br>
> <br>
> What is your goal with such dictionary?<br>
> It's now in the Trunk with no users. And I think there might be a better<br>
> way to do what you want to achieve than copying all those methods.<br>
> <br>
> <br>
> Levente<br>
> <br>
> On Mon, 27 Dec 2021, commits@source.squeak.org wrote:<br>
> <br>
> > Christoph Thiede uploaded a new version of Collections to project The Trunk:<br>
> > <a href="http://source.squeak.org/trunk/Collections-ct.972.mcz" id="LPlnk601345" previewremoved="true">
http://source.squeak.org/trunk/Collections-ct.972.mcz</a><br>
> ><br>
> > ==================== Summary ====================<br>
> ><br>
> > Name: Collections-ct.972<br>
> > Author: ct<br>
> > Time: 27 December 2021, 1:19:57.212181 am<br>
> > UUID: f740e1ad-4410-0745-b615-2986366b7e75<br>
> > Ancestors: Collections-tonyg.971<br>
> ><br>
> > Adds PluggableWeakKeyDictionary, the logical combination of PluggableDictionary and WeakKeyDictionary. All methods are copied literally from PluggableDictionary, but the class inherits from WeakKeyDictionary rather than from Dictionary.<br>
> ><br>
> > I do not like all the duplication myself but cannot think of a better solution without using composition (slow, breaking design change) or traits (breaking design change).<br>
> ><br>
> > =============== Diff against Collections-tonyg.971 ===============<br>
> ><br>
> > Item was added:<br>
> > + WeakKeyDictionary subclass: #PluggableWeakKeyDictionary<br>
> > +      instanceVariableNames: 'hashBlock equalBlock'<br>
> > +      classVariableNames: ''<br>
> > +      poolDictionaries: ''<br>
> > +      category: 'Collections-Weak'!<br>
> > +<br>
> > + !PluggableWeakKeyDictionary commentStamp: 'ct 12/27/2021 01:07' prior: 0!<br>
> > + I combine the features of PluggableDictionary and WeakKeyDictionary, i.e., clients can supply custom blocks for comparing and hasing my keys, and I hold weakly on my keys.!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary class>>integerDictionary (in category 'instance creation') -----<br>
> > + integerDictionary<br>
> > +      ^ self new hashBlock: [:integer | integer hash \\ 1064164 * 1009]!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>= (in category 'comparing') -----<br>
> > + = anObject<br>
> > +      "Two dictionaries are equal if<br>
> > +       (a) they are the same 'kind' of thing.<br>
> > +       (b) they have the same set of keys.<br>
> > +       (c) for each (common) key, they have the same value"<br>
> > +<br>
> > +      self == anObject ifTrue: [ ^true ].<br>
> > +      self species == anObject species ifFalse: [ ^false ].<br>
> > +      hashBlock = anObject hashBlock ifFalse: [ ^false ].<br>
> > +      equalBlock = anObject equalBlock ifFalse: [ ^false ].<br>
> > +      self size = anObject size ifFalse: [ ^false ].<br>
> > +      self associationsDo: [ :association |<br>
> > +              (anObject at: association key ifAbsent: [ ^false ]) = association value<br>
> > +                      ifFalse: [ ^false ] ].<br>
> > +      ^true!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>collect: (in category 'enumerating') -----<br>
> > + collect: aBlock<br>
> > +      "Evaluate aBlock with each of my values as the argument.  Collect the resulting values into a collection that is like me. Answer with the new collection."<br>
> > +<br>
> > +      | newCollection |<br>
> > +      newCollection := (self species new: self size)<br>
> > +              hashBlock: hashBlock;<br>
> > +              equalBlock: equalBlock;<br>
> > +              yourself.<br>
> > +      self associationsDo: [ :each |<br>
> > +              newCollection at: each key put: (aBlock value: each value) ].<br>
> > +      ^newCollection<br>
> > +<br>
> > + !<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>copyEmpty (in category 'copying') -----<br>
> > + copyEmpty<br>
> > +<br>
> > +      ^super copyEmpty<br>
> > +              hashBlock: hashBlock;<br>
> > +              equalBlock: equalBlock;<br>
> > +              yourself!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>equalBlock (in category 'accessing') -----<br>
> > + equalBlock<br>
> > +      "Return the block used for comparing the elements in the receiver."<br>
> > +      ^equalBlock!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>equalBlock: (in category 'accessing') -----<br>
> > + equalBlock: aBlock<br>
> > +      "Set a new equality block. The block must accept two arguments and return true if the argumets are considered to be equal, false otherwise"<br>
> > +      equalBlock := aBlock.!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>hashBlock (in category 'accessing') -----<br>
> > + hashBlock<br>
> > +      "Return the block used for hashing the elements in the receiver."<br>
> > +      ^hashBlock!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>hashBlock: (in category 'accessing') -----<br>
> > + hashBlock: aBlock<br>
> > +      "Set a new hash block. The block must accept one argument and must return the hash value of the given argument."<br>
> > +      hashBlock := aBlock.!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>scanFor: (in category 'private') -----<br>
> > + scanFor: anObject<br>
> > +      "Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or raise an error if no slot is found. This method will be overridden in various subclasses
 that have different interpretations for matching elements."<br>
> > +<br>
> > +      | index start size |<br>
> > +      index := start := (hashBlock<br>
> > +              ifNil: [ anObject hash ]<br>
> > +              ifNotNil: [ hashBlock value: anObject ]) \\ (size := array size) + 1.<br>
> > +      [<br>
> > +              | element |<br>
> > +              ((element := array at: index) == nil or: [<br>
> > +                      equalBlock<br>
> > +                              ifNil: [ element key = anObject ]<br>
> > +                              ifNotNil: [ equalBlock value: element key value: anObject ] ])<br>
> > +                      ifTrue: [ ^index ].<br>
> > +              (index := index \\ size + 1) = start ] whileFalse.<br>
> > +      self errorNoFreeSpace!<br>
> ><br>
> > Item was added:<br>
> > + ----- Method: PluggableWeakKeyDictionary>>scanForEmptySlotFor: (in category 'private') -----<br>
> > + scanForEmptySlotFor: anObject<br>
> > +      "Scan the key array for the first slot containing an empty slot (indicated by a nil). Answer the index of that slot. This method will be overridden in various subclasses that have different interpretations for matching elements."<br>
> > +<br>
> > +      | index start size |<br>
> > +      index := start := (hashBlock<br>
> > +              ifNil: [ anObject hash ]<br>
> > +              ifNotNil: [ hashBlock value: anObject ]) \\ (size := array size) + 1.<br>
> > +      [<br>
> > +              (array at: index) ifNil: [ ^index ].<br>
> > +              (index := index \\ size + 1) = start ] whileFalse.<br>
> > +      self errorNoFreeSpace!<br>
> <br>
<br>
> <br>
<br>
<br>
</div>
</span></span></div>
</div>
</blockquote>
</div>
</div>
</body>
</html>