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!
|
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 |
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 |
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 > > |
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:
|
In reply to this post by Levente Uzonyi
Hi all,
thanks for all the opinions! :-)
to something like that:
So I have the feeling that he would also recommend refactoring
to:
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!
|
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 |
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:
Carpe Squeak!
|
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 |
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. :-) 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 > > > > > > |
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 |
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 > |
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!
|
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 |
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 >> |
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. |
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 > |
> For example, passing the object to the condition block (or even the result > 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 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: |
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 |
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. 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 > > > > > > |
Free forum by Nabble | Edit this page |