#identityCaseOf:

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

Re: #identityCaseOf:

Christoph Thiede

Woah, I didn't know that this topic has been such a hot potato. :-)


In my opinion, people can always abuse a (domain-specific) language to write bad code and you cannot really stop them from doing so by limiting the features of the language. Instead of banning a protocol, people should understand *why* and *when* it is a bad idea to use them. #caseOf: & Co. can be used and can be abused, so I vote for keeping and legalizing it (otherwise we have to destroy every bread knife, too).
If we stigmatize #caseOf:, we could also stigmatize or even deprecate #isKindOf: because very often, it is abused - but still, it can be useful in many situations where you need metaprogramming indeed, for example, Exception class >> #handles:.
LBNL, I often consider both concepts as the first step of a larger refactoring. Alone for this purpose, I would like to keep these selectors.

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von tim Rowledge <[hidden email]>
Gesendet: Sonntag, 28. März 2021 19:07:58
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] #identityCaseOf:
 


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





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

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

Christoph Thiede
In reply to this post by David T. Lewis

I like these proposals, too. At the moment, it is very hard to implement any change in #caseOf:[otherwise:] because the Compiler optimization has to be adjusted. We should make this optimization selective analogously to #ifTrue:, #whileTrue:. etc., so that all the fancy examples you have mentioned before will be compiled as regular message sends unless someone feels like optimizing them.

What do you think? :-)

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von David T. Lewis <[hidden email]>
Gesendet: Montag, 29. März 2021 01:32:26
An: [hidden email]; The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] Extending the functionality of caseOf: (was: #identityCaseOf:)
 
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




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

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

Christoph Thiede
In reply to this post by Levente Uzonyi

Hi Levente,


IMHO a DSL is very much about syntactic sugar. If we obviate it, we impede the development of richer and higher-level language concepts that abstract from repetitive and uninteresting basics such as the temporary variable in your example. Just my two cents. :-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von Levente Uzonyi <[hidden email]>
Gesendet: Dienstag, 30. März 2021 22:21:00
An: [hidden email]; The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] Extending the functionality of caseOf: (was: #identityCaseOf:)
 
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
>       >
>
>
>
>


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

Re: #identityCaseOf:

Jakob Reschke
In reply to this post by Christoph Thiede
Having started out with Delphi, I do not mind caseOf:. But I more often wish for Lisp's cond. true caseOf: looks somehow strange and like a hack to me—just a feeling—though I admit it does make sense when I force myself to read it as English: "For the true case of the following, do..."

Regarding letting people choose their protocols, just make sure that Smalltalk does not end up being a write-only-for-me language like Perl. :-)
I think there has already been this discussion about how many shortcuts and utility methods should be in the language and which should rather stay out.


Am Mi., 7. Apr. 2021 um 17:53 Uhr schrieb Thiede, Christoph <[hidden email]>:

Woah, I didn't know that this topic has been such a hot potato. :-)


In my opinion, people can always abuse a (domain-specific) language to write bad code and you cannot really stop them from doing so by limiting the features of the language. Instead of banning a protocol, people should understand *why* and *when* it is a bad idea to use them. #caseOf: & Co. can be used and can be abused, so I vote for keeping and legalizing it (otherwise we have to destroy every bread knife, too).
If we stigmatize #caseOf:, we could also stigmatize or even deprecate #isKindOf: because very often, it is abused - but still, it can be useful in many situations where you need metaprogramming indeed, for example, Exception class >> #handles:.
LBNL, I often consider both concepts as the first step of a larger refactoring. Alone for this purpose, I would like to keep these selectors.

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von tim Rowledge <[hidden email]>
Gesendet: Sonntag, 28. März 2021 19:07:58
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] #identityCaseOf:
 


> 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
|

Re: #identityCaseOf:

marcel.taeumel
Hi all!

#caseOf:(otherwise:) has its uses. I would probably rarely use it for lookup tables with less than 3-4 rows, especially when there is no reason to believe that the list will grow soon. But even then, I tend to use ad-hoc dictionaries for the lookup, which might be not-so-good for performance.

In my opinion, good examples for #caseOf:(otherwise:) include (but are not limited to):

PNMReadWriter >> #nextImage
CompiledCode >> #scanFor:
Character >> #isSeparator
Context >> #exceptionMessage
DoItFirst >> #keyFor:
HandMorph >> #processEvents
Inspector >> #inspectorKey:from:
ProcessBrowser >> #processListKey:from:
MimeConverter class >> #forEncoding:
WebUtils class >> #jsonDecode:

Well, not-so-good examples include (but are not limited to):

MenuMorph >> #handleFiltering:
Text >> #format:
CompiledMethod >> #scanForInstructionPattern:

There, I would opt for the good-ol' #ifTrue:ifFalse:. Or maybe an "extract method"-refactoring might improve the intend and readability of those.

Any change to #caseOf: MUST account for the Decompiler. Even the introduction of an #identityCaseOf:(otherwise:).

"true caseOf: { ... }" is an anti pattern. Please don't do that. :-)

Best,
Marcel

Am 07.04.2021 20:13:45 schrieb Jakob Reschke <[hidden email]>:

Having started out with Delphi, I do not mind caseOf:. But I more often wish for Lisp's cond. true caseOf: looks somehow strange and like a hack to me—just a feeling—though I admit it does make sense when I force myself to read it as English: "For the true case of the following, do..."

Regarding letting people choose their protocols, just make sure that Smalltalk does not end up being a write-only-for-me language like Perl. :-)
I think there has already been this discussion about how many shortcuts and utility methods should be in the language and which should rather stay out.


Am Mi., 7. Apr. 2021 um 17:53 Uhr schrieb Thiede, Christoph <[hidden email]>:

Woah, I didn't know that this topic has been such a hot potato. :-)


In my opinion, people can always abuse a (domain-specific) language to write bad code and you cannot really stop them from doing so by limiting the features of the language. Instead of banning a protocol, people should understand *why* and *when* it is a bad idea to use them. #caseOf: & Co. can be used and can be abused, so I vote for keeping and legalizing it (otherwise we have to destroy every bread knife, too).
If we stigmatize #caseOf:, we could also stigmatize or even deprecate #isKindOf: because very often, it is abused - but still, it can be useful in many situations where you need metaprogramming indeed, for example, Exception class >> #handles:.
LBNL, I often consider both concepts as the first step of a larger refactoring. Alone for this purpose, I would like to keep these selectors.

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von tim Rowledge <[hidden email]>
Gesendet: Sonntag, 28. März 2021 19:07:58
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] #identityCaseOf:
 


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






12