#identityCaseOf:

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

#identityCaseOf:

Christoph Thiede

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



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

David T. Lewis
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


Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

timrowledge
In reply to this post by Christoph Thiede


> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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; [hidden email]; 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




Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Levente Uzonyi
In reply to this post by Christoph Thiede
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
>
>

Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Balázs Kósi
In reply to this post by Christoph Thiede
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 <[hidden email]> 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




Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Christoph Thiede
In reply to this post by Levente Uzonyi

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. :-)


Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Levente Uzonyi <[hidden email]>
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
>
>


Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Tobias Pape
In reply to this post by timrowledge
Hi


> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>
>
>
>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Christoph Thiede
In reply to this post by Balázs Kósi

Hi Balázs,


absolutely right. Thanks for your hint, I just committed the change to SimulationStudio. [1]

Best,
Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Balázs Kósi <[hidden email]>
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 <[hidden email]> 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




Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Levente Uzonyi
In reply to this post by Tobias Pape
On Sun, 28 Mar 2021, Tobias Pape wrote:

> Hi
>
>
>> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>>
>>
>>
>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Levente Uzonyi
In reply to this post by Christoph Thiede
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 <[hidden email]> im Auftrag von Levente Uzonyi <[hidden email]>
> 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
> >
> >
>
>

Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Tobias Pape
In reply to this post by Levente Uzonyi


> On 28. Mar 2021, at 16:03, Levente Uzonyi <[hidden email]> wrote:
>
> On Sun, 28 Mar 2021, Tobias Pape wrote:
>
>> Hi
>>
>>
>>> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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



Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Tobias Pape
In reply to this post by Levente Uzonyi


> On 28. Mar 2021, at 16:03, Levente Uzonyi <[hidden email]> wrote:
>
> On Sun, 28 Mar 2021, Tobias Pape wrote:
>
>> Hi
>>
>>
>>> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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
>



Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Christoph Thiede

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 <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
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 <[hidden email]> wrote:
>
> On Sun, 28 Mar 2021, Tobias Pape wrote:
>
>> Hi
>>
>>
>>> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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
>





Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Levente Uzonyi
In reply to this post by Tobias Pape
On Sun, 28 Mar 2021, Tobias Pape wrote:

>
>
>> On 28. Mar 2021, at 16:03, Levente Uzonyi <[hidden email]> wrote:
>>
>> On Sun, 28 Mar 2021, Tobias Pape wrote:
>>
>>> Hi
>>>
>>>
>>>> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

Levente Uzonyi
In reply to this post by Tobias Pape
On Sun, 28 Mar 2021, Tobias Pape wrote:

>
>
>> On 28. Mar 2021, at 16:03, Levente Uzonyi <[hidden email]> wrote:
>>
>> On Sun, 28 Mar 2021, Tobias Pape wrote:
>>
>>> Hi
>>>
>>>
>>>> On 28. Mar 2021, at 07:12, tim Rowledge <[hidden email]> wrote:
>>>>> On 2021-03-27, at 11:47 AM, Thiede, Christoph <[hidden email]> 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
>>

Reply | Threaded
Open this post in threaded view
|

Re: #identityCaseOf:

timrowledge
In reply to this post by Christoph Thiede


> On 2021-03-28, at 4:09 AM, Thiede, Christoph <[hidden email]> 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; [hidden email]; http://www.rowledge.org/tim
Useful random insult:- Not enough sense to come in out of the rain.



Reply | Threaded
Open this post in threaded view
|

Extending the functionality of caseOf: (was: #identityCaseOf:)

David T. Lewis
In reply to this post by Levente Uzonyi
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
>


Reply | Threaded
Open this post in threaded view
|

Re: Extending the functionality of caseOf: (was: #identityCaseOf:)

Chris Muller-3
> 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
>




Reply | Threaded
Open this post in threaded view
|

Re: Extending the functionality of caseOf: (was: #identityCaseOf:)

David T. Lewis
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


Reply | Threaded
Open this post in threaded view
|

Re: Extending the functionality of caseOf: (was: #identityCaseOf:)

Levente Uzonyi
In reply to this post by Chris Muller-3
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
>       >
>
>
>
>

12