[Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
Hi guys let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all. | z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z => "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] " there is one user which I fixing right now. Stef
On Fri, 11 Feb 2011, stephane ducasse wrote:
Hi guys
let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all.
| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z
=> "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] "
there is one user which I fixing right now.
IMHO you shouldn't remove it. There are a lot more users of this method (16 in the Pharo image I have and a lot more in external packages), but this method is inlined by the compiler, so you won't see it in the senders list. Try this instead: SystemNavigation default browseMethodsWithSourceString: 'caseOf:'. Using #detect: and #detect:ifNone: with a dynamically created array is a _lot_ slower than the inlined #caseOf: and #caseOf:otherwise:. For example: [ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '1,790,000 per second.'. [ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '66,600 per second.' ~27x slowdown in this case. Levente
On 12 February 2011 18:41, Levente Uzonyi <leves@elte.hu> wrote:
On Fri, 11 Feb 2011, stephane ducasse wrote:
Hi guys
let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all.
| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z
=> "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] "
there is one user which I fixing right now.
IMHO you shouldn't remove it. There are a lot more users of this method (16 in the Pharo image I have and a lot more in external packages), but this method is inlined by the compiler, so you won't see it in the senders list. Try this instead:
SystemNavigation default browseMethodsWithSourceString: 'caseOf:'.
Using #detect: and #detect:ifNone: with a dynamically created array is a _lot_ slower than the inlined #caseOf: and #caseOf:otherwise:. For example:
[ 1 to: 10 do: [ :each |     each         caseOf: {             [ 1 ] -> [ $a ].             [ 2 ] -> [ $b ].             [ 3 ] -> [ $c ].             [ 4 ] -> [ $d ].             [ 5 ] -> [ $e ] }         otherwise: [ $x ] ] ] bench. '1,790,000 per second.'.
[ 1 to: 10 do: [ :each | Â Â Â Â ({ Â Â Â Â Â Â Â Â [ 1 ] -> [ $a ]. Â Â Â Â Â Â Â Â [ 2 ] -> [ $b ]. Â Â Â Â Â Â Â Â [ 3 ] -> [ $c ]. Â Â Â Â Â Â Â Â [ 4 ] -> [ $d ]. Â Â Â Â Â Â Â Â [ 5 ] -> [ $e ] } Â Â Â Â Â Â Â Â Â Â Â Â detect: [ :ea | ea key value = each ] Â Â Â Â Â Â Â Â Â Â Â Â ifNone: [ [ $x ] ]) value ] ] bench. '66,600 per second.'
~27x slowdown in this case.
oh come on. Switch statement should live where it belongs to: C code. Why we should support this ridiculous syntax constructs in smalltalk? IMO: All users of such code should die. And i don't care if they are working fast or not.. This is plainly against the spirit of smalltalk.
Levente
-- Best regards, Igor Stasenko AKA sig.
On Sat, 12 Feb 2011, Igor Stasenko wrote:
oh come on. Switch statement should live where it belongs to: C code.
It's nothing like C's switch statement, and I'm sure you know that.
Why we should support this ridiculous syntax constructs in smalltalk?
What's so ridiculous about it?
IMO: All users of such code should die. And i don't care if they are working fast or not.. This is plainly against the spirit of smalltalk.
Okay, then enlighten me please, how one should rewrite the following dispatch without #caseOf:? You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these, a predefined value has to be set to an instance variable depending on the integer. The current code is like: foo caseOf: { [ 0 ] -> [ var2 := x ]. [ 83 ] -> [ var13 := x ]. ... Should I use #detect: to find the variable? Or a dictionary? Maybe a binary search on an array? Or a bunch of #ifTrue:ifFalse: conditionals? Maybe a separate class for each variable and let the VM do the dispatch? How should I set the value? With #perform:? Or #instVarAt:put:? Levente
Levente
-- Best regards, Igor Stasenko AKA sig.
On 13 February 2011 00:17, Levente Uzonyi <leves@elte.hu> wrote:
On Sat, 12 Feb 2011, Igor Stasenko wrote:
oh come on. Switch statement should live where it belongs to: C code.
It's nothing like C's switch statement, and I'm sure you know that.
Why we should support this ridiculous syntax constructs in smalltalk?
What's so ridiculous about it?
IMO: All users of such code should die. And i don't care if they are working fast or not.. This is plainly against the spirit of smalltalk.
Okay, then enlighten me please, how one should rewrite the following dispatch without #caseOf:?
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these, a predefined value has to be set to an instance variable depending on the integer. The current code is like:
foo caseOf: { Â Â Â Â [ 0 ] -> [ var2 := x ]. Â Â Â Â [ 83 ] -> [ var13 := x ]. Â Â Â Â ...
Should I use #detect: to find the variable? Or a dictionary? Maybe a binary search on an array? Or a bunch of #ifTrue:ifFalse: conditionals? Maybe a separate class for each variable and let the VM do the dispatch? How should I set the value? With #perform:? Or #instVarAt:put:?
Don't try to convince me that there are sort of problems which can be solved only by using case statement :) First, get rid of these integers in your code. Use symbolic names. And then for dispatching using parameter, there is a #peform: primitive. So, then switch statement will be turned into: self peform: (self decode: someInteger) and this is how it should look like. And again, if you can avoid using integers at all, use symbols , so you don't have to decode/translate them. Just do #perform. I thought that this is obvious for you.
Levente
-- Best regards, Igor Stasenko AKA sig.
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
We all know that it can be solved, but the solution won't be nicer at all, instead it will be a lot slower.
First, get rid of these integers in your code. Use symbolic names. And then for dispatching using parameter, there is a #peform: primitive.
The integers are from a binary stream, so I can't do much about it.
So, then switch statement will be turned into:
self peform: (self decode: someInteger)
and this is how it should look like. And again, if you can avoid using integers at all, use symbols , so you don't have to decode/translate them. Just do #perform.
I thought that this is obvious for you.
What you wrote here is obvious, but not an answer to my question. What should #decode: do? Use #detect:? Or a dictionary? Maybe a binary search on an array? Or should it be a bunch of #ifTrue:ifFalse: conditionals? (I guess the separate class per integer idea is abandoned, but who knows.) Also note that #perform:with: is ~11x slower on Cog than sending a message. And a send is a lot slower (~5.5x IIRC) than a direct assignment. That's ~55x combined slowdown not counting the integer->selector matching. Levente
Levente
-- Best regards, Igor Stasenko AKA sig.
On 13 February 2011 00:59, Levente Uzonyi <leves@elte.hu> wrote:
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
We all know that it can be solved, but the solution won't be nicer at all, instead it will be a lot slower.
First, get rid of these integers in your code. Use symbolic names. And then for dispatching using parameter, there is a #peform: primitive.
The integers are from a binary stream, so I can't do much about it.
Oh yeah? Too bad for you then.
So, then switch statement will be turned into:
self peform: (self decode: someInteger)
and this is how it should look like. And again, if you can avoid using integers at all, use symbols , so you don't have to decode/translate them. Just do #perform.
I thought that this is obvious for you.
What you wrote here is obvious, but not an answer to my question. What should #decode: do? Use #detect:? Or a dictionary? Maybe a binary search on an array? Or should it be a bunch of #ifTrue:ifFalse: conditionals? (I guess the separate class per integer idea is abandoned, but who knows.)
I don't care. You should encapsulate them into something , which has a meaning. Use bare numbers without any docs/comments/explanations to C.
Also note that #perform:with: is ~11x slower on Cog than sending a message. And a send is a lot slower (~5.5x IIRC) than a direct assignment. That's ~55x combined slowdown not counting the integer->selector matching.
Slower comparing to someone who will read your code and try to understand what it does. THAT WILL BE SLOWER and that is most precious resource we have, not the CPU time. Please read the http://www.c2.com/cgi/wiki?PrematureOptimization :)
Levente
-- Best regards, Igor Stasenko AKA sig.
On Sun, 13 Feb 2011, Igor Stasenko wrote:
On 13 February 2011 00:59, Levente Uzonyi <leves@elte.hu> wrote:
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
We all know that it can be solved, but the solution won't be nicer at all, instead it will be a lot slower.
First, get rid of these integers in your code. Use symbolic names. And then for dispatching using parameter, there is a #peform: primitive.
The integers are from a binary stream, so I can't do much about it.
Oh yeah? Too bad for you then.
And everyone trying to implement a binary protocol efficiently.
So, then switch statement will be turned into:
self peform: (self decode: someInteger)
and this is how it should look like. And again, if you can avoid using integers at all, use symbols , so you don't have to decode/translate them. Just do #perform.
I thought that this is obvious for you.
What you wrote here is obvious, but not an answer to my question. What should #decode: do? Use #detect:? Or a dictionary? Maybe a binary search on an array? Or should it be a bunch of #ifTrue:ifFalse: conditionals? (I guess the separate class per integer idea is abandoned, but who knows.)
I don't care. You should encapsulate them into something , which has a meaning. Use bare numbers without any docs/comments/explanations to C.
Also note that #perform:with: is ~11x slower on Cog than sending a message. And a send is a lot slower (~5.5x IIRC) than a direct assignment. That's ~55x combined slowdown not counting the integer->selector matching.
Slower comparing to someone who will read your code and try to understand what it does. THAT WILL BE SLOWER and that is most precious resource we have, not the CPU time.
Is #caseOf: unreadable? No it's not. You just don't like it for some unknown reason. And you're not willing to tell what's your problem with it.
Please read the http://www.c2.com/cgi/wiki?PrematureOptimization :)
I know what's premature optimization. What I do differently than other people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc. - I optimize library code which is expected to be heavily used - I like to optimize code Levente
Levente
-- Best regards, Igor Stasenko AKA sig.
El dom, 13-02-2011 a las 02:26 +0100, Levente Uzonyi escribió:
I know what's premature optimization.
It appear that you know but doesn't understand. See below.
What I do differently than other people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc.
This *is* premature optimization. Why? because you're programming with the performance in mind *all* the time, since the first second you start programming! And not only that, it relies on a specific VM implementation, the squeak one. Presumes that the given messages are *more efficient* (just because you know that the squeak compiler/vm combination makes them so). But this could be wrong or at least useless in other vm (like GNU or Gemstone). So by definition it is premature optimization. Lastly, to program like you (and not like others, Igor and I and most people I think) we should have in the head the specifics of the vm implementation and a handy list of the inlined messages of the vm. This is the job of the JIT, not from the developer!
- I optimize library code which is expected to be heavily used
This the time and usage will tell
- I like to optimize code
Prematurely it appears! Cheers -- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
On Sat, 12 Feb 2011, Miguel Cobá wrote:
El dom, 13-02-2011 a las 02:26 +0100, Levente Uzonyi escribió:
I know what's premature optimization.
It appear that you know but doesn't understand. See below.
What I do differently than other people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc.
This *is* premature optimization. Why? because you're programming with the performance in mind *all* the time, since the first second you start programming!
What you fail to realize is that the code is not longer or complicated at all. It has zero extra cost for you to read it, for me to write it, for the machine to execute it.
And not only that, it relies on a specific VM implementation, the squeak one. Presumes that the given messages are *more efficient* (just because you know that the squeak compiler/vm combination makes them so). But this could be wrong or at least useless in other vm (like GNU or Gemstone). So by definition it is premature optimization.
That's right, I don't care about other VMs. Do the developers of VW, Gemstone or GNU Smalltalk care about how their code will perform on SqueakVM or CogVM? Hardly.
Lastly, to program like you (and not like others, Igor and I and most people I think) we should have in the head the specifics of the vm implementation and a handy list of the inlined messages of the vm.
That list is surprisingly short. There are more keywords or syntax constructs in C/C++/Java/C#/Python/whatever than these special messages.
This is the job of the JIT, not from the developer!
Show me the JIT that does it. Levente
- I optimize library code which is expected to be heavily used
This the time and usage will tell
- I like to optimize code
Prematurely it appears!
Cheers
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
El dom, 13-02-2011 a las 02:58 +0100, Levente Uzonyi escribió:
On Sat, 12 Feb 2011, Miguel Cobá wrote:
El dom, 13-02-2011 a las 02:26 +0100, Levente Uzonyi escribió:
I know what's premature optimization.
It appear that you know but doesn't understand. See below.
What I do differently than other people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc.
This *is* premature optimization. Why? because you're programming with the performance in mind *all* the time, since the first second you start programming!
What you fail to realize is that the code is not longer or complicated at all. It has zero extra cost for you to read it, for me to write it, for the machine to execute it.
And not only that, it relies on a specific VM implementation, the squeak one. Presumes that the given messages are *more efficient* (just because you know that the squeak compiler/vm combination makes them so). But this could be wrong or at least useless in other vm (like GNU or Gemstone). So by definition it is premature optimization.
That's right, I don't care about other VMs. Do the developers of VW, Gemstone or GNU Smalltalk care about how their code will perform on SqueakVM or CogVM? Hardly.
Lastly, to program like you (and not like others, Igor and I and most people I think) we should have in the head the specifics of the vm implementation and a handy list of the inlined messages of the vm.
That list is surprisingly short. There are more keywords or syntax constructs in C/C++/Java/C#/Python/whatever than these special messages.
The list of registers in a intel 386 cpu is short too but that doesn't means that everyone must learn what registers are better for what kind of datatype performance-wise. Again this is not the task for the developer. As everyone trying to do OO programing, the implementation details are irrelevant when programming.
This is the job of the JIT, not from the developer!
Show me the JIT that does it.
I said that is the *job* of the JIT not that every JIT can do it/should do it/does it.
Levente
- I optimize library code which is expected to be heavily used
This the time and usage will tell
- I like to optimize code
Prematurely it appears!
Cheers
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
On Sat, 12 Feb 2011, Miguel Cobá wrote:
El dom, 13-02-2011 a las 02:58 +0100, Levente Uzonyi escribió:
On Sat, 12 Feb 2011, Miguel Cobá wrote:
El dom, 13-02-2011 a las 02:26 +0100, Levente Uzonyi escribió:
I know what's premature optimization.
It appear that you know but doesn't understand. See below.
What I do differently than other people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc.
This *is* premature optimization. Why? because you're programming with the performance in mind *all* the time, since the first second you start programming!
What you fail to realize is that the code is not longer or complicated at all. It has zero extra cost for you to read it, for me to write it, for the machine to execute it.
And not only that, it relies on a specific VM implementation, the squeak one. Presumes that the given messages are *more efficient* (just because you know that the squeak compiler/vm combination makes them so). But this could be wrong or at least useless in other vm (like GNU or Gemstone). So by definition it is premature optimization.
That's right, I don't care about other VMs. Do the developers of VW, Gemstone or GNU Smalltalk care about how their code will perform on SqueakVM or CogVM? Hardly.
Lastly, to program like you (and not like others, Igor and I and most people I think) we should have in the head the specifics of the vm implementation and a handy list of the inlined messages of the vm.
That list is surprisingly short. There are more keywords or syntax constructs in C/C++/Java/C#/Python/whatever than these special messages.
The list of registers in a intel 386 cpu is short too but that doesn't means that everyone must learn what registers are better for what kind of datatype performance-wise. Again this is not the task for the
I'm sure, every assembly programmer has to learn it, but how is it related to the messages that are inlined by the compiler?
developer. As everyone trying to do OO programing, the implementation details are irrelevant when programming.
Are you serious?
This is the job of the JIT, not from the developer!
Show me the JIT that does it.
I said that is the *job* of the JIT not that every JIT can do it/should do it/does it.
Be honest, there's no JIT for a Pharo image, that can do this. Levente
Levente
- I optimize library code which is expected to be heavily used
This the time and usage will tell
- I like to optimize code
Prematurely it appears!
Cheers
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere. Having such strong arguments (for or against) is not helpful for anybody. We all know using #caseOf:otherwise: it's not exactly good style, but sometimes you need to compromise between design and efficiency, and having simple and efficient constructs such as #caseOf: is very good IMHO. You are free to avoid them if your projects don't need it, and if you happen to need extra performance you can always build your own JIT, right? :) But please don't ban people who are willing to sacrifice a little readability for performance reasons. Thanks. Best regards. Richo 2011/2/12 Levente Uzonyi <leves@elte.hu>
On Sat, 12 Feb 2011, Miguel Cobá wrote:
El dom, 13-02-2011 a las 02:58 +0100, Levente Uzonyi escribió:
On Sat, 12 Feb 2011, Miguel Cobá wrote:
El dom, 13-02-2011 a las 02:26 +0100, Levente Uzonyi escribió:
I know what's premature optimization.
It appear that you know but doesn't understand. See below.
What I do differently than other
people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc.
This *is* premature optimization. Why? because you're programming with the performance in mind *all* the time, since the first second you start programming!
What you fail to realize is that the code is not longer or complicated at all. It has zero extra cost for you to read it, for me to write it, for the machine to execute it.
And not only that, it relies on a specific VM implementation, the squeak one. Presumes that the given messages are *more efficient* (just because you know that the squeak compiler/vm combination makes them so). But this could be wrong or at least useless in other vm (like GNU or Gemstone). So by definition it is premature optimization.
That's right, I don't care about other VMs. Do the developers of VW, Gemstone or GNU Smalltalk care about how their code will perform on SqueakVM or CogVM? Hardly.
Lastly, to program like you (and not like others, Igor and I and most people I think) we should have in the head the specifics of the vm implementation and a handy list of the inlined messages of the vm.
That list is surprisingly short. There are more keywords or syntax constructs in C/C++/Java/C#/Python/whatever than these special messages.
The list of registers in a intel 386 cpu is short too but that doesn't means that everyone must learn what registers are better for what kind of datatype performance-wise. Again this is not the task for the
I'm sure, every assembly programmer has to learn it, but how is it related to the messages that are inlined by the compiler?
developer. As everyone trying to do OO programing, the implementation
details are irrelevant when programming.
Are you serious?
This is the job of the JIT, not from the developer!
Show me the JIT that does it.
I said that is the *job* of the JIT not that every JIT can do it/should do it/does it.
Be honest, there's no JIT for a Pharo image, that can do this.
Levente
Levente
- I optimize library code which is expected to be heavily used
This the time and usage will tell
- I like to optimize code
Prematurely it appears!
Cheers
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
-- Miguel Cobá http://twitter.com/MiguelCobaMtz http://miguel.leugim.com.mx
On 13 February 2011 04:05, Ricardo Moran <richi.moran@gmail.com> wrote:
But please don't ban people who are willing to sacrifice a little readability for performance reasons. Thanks.
Then C language is your choice! It is full of such sacrifices :) But can i ask you to not turn smalltalk into C , please?
Best regards. Richo
-- Best regards, Igor Stasenko AKA sig.
Hi ricardo, igor and levente I really want to remove caseOf: since years. Why: - conceptually wrong (even if this may be nice to have for $A and numbers) - to me it looks like coming from another age - never needs to use it: of course other people may of course - Three less methods in Object - only available in Squeak/Pharo - but more more more important: makes the compiler, decompiler, inliner....., more complex. I want opal to get out because we need a better infrastructure: simpler, better compiler. - Ideally I would prefer that we can extend the compiler with it and that people needed it just ship a plugin with their code. Marcus is opal dealing with caseOf:? I did not want to have a war. I thought that it was pretty obvious that we do not really need that. Stef
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere. Having such strong arguments (for or against) is not helpful for anybody. We all know using #caseOf:otherwise: it's not exactly good style, but sometimes you need to compromise between design and efficiency, and having simple and efficient constructs such as #caseOf: is very good IMHO. You are free to avoid them if your projects don't need it, and if you happen to need extra performance you can always build your own JIT, right? :) But please don't ban people who are willing to sacrifice a little readability for performance reasons. Thanks.
Best regards. Richo
Hi, I also think we do not need caseOf: in the default distribution. It is probably useful for some cases (like dealing with integers from some external source as mentioned by Levente), but those cases are so rare that we should not affect everyone with this message. Cheers, Doru On 13 Feb 2011, at 08:57, Stéphane Ducasse wrote:
Hi ricardo, igor and levente
I really want to remove caseOf: since years. Why: - conceptually wrong (even if this may be nice to have for $A and numbers) - to me it looks like coming from another age - never needs to use it: of course other people may of course - Three less methods in Object - only available in Squeak/Pharo - but more more more important: makes the compiler, decompiler, inliner....., more complex. I want opal to get out because we need a better infrastructure: simpler, better compiler. - Ideally I would prefer that we can extend the compiler with it and that people needed it just ship a plugin with their code.
Marcus is opal dealing with caseOf:?
I did not want to have a war. I thought that it was pretty obvious that we do not really need that.
Stef
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere. Having such strong arguments (for or against) is not helpful for anybody. We all know using #caseOf:otherwise: it's not exactly good style, but sometimes you need to compromise between design and efficiency, and having simple and efficient constructs such as #caseOf: is very good IMHO. You are free to avoid them if your projects don't need it, and if you happen to need extra performance you can always build your own JIT, right? :) But please don't ban people who are willing to sacrifice a little readability for performance reasons. Thanks.
Best regards. Richo
-- www.tudorgirba.com "Value is always contextual."
On 13 February 2011 09:05, Tudor Girba <tudor.girba@gmail.com> wrote:
Hi,
I also think we do not need caseOf: in the default distribution.
It is probably useful for some cases (like dealing with integers from some external source as mentioned by Levente), but those cases are so rare that we should not affect everyone with this message.
Yes, i know the case where its useful: it used by VMMaker code generator, which translating caseOf: to C switch statement :)
Cheers, Doru
On 13 Feb 2011, at 08:57, Stéphane Ducasse wrote:
Hi ricardo, igor and levente
I really want to remove caseOf: since years. Why:    - conceptually wrong (even if this may be nice to have for $A and numbers)    - to me it looks like coming from another age    - never needs to use it: of course other people may of course    - Three less methods in Object    - only available in Squeak/Pharo    - but more more more important:        makes the compiler, decompiler, inliner....., more complex.    I want opal to get out because we need a better infrastructure: simpler, better compiler.    - Ideally I would prefer that we can extend the compiler with it and that people needed it just ship a plugin with    their code.
Marcus is opal dealing with caseOf:?
I did not want to have a war. I thought that it was pretty obvious that we do not really need that.
Stef
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere. Having such strong arguments (for or against) is not helpful for anybody. We all know using #caseOf:otherwise: it's not exactly good style, but sometimes you need to compromise between design and efficiency, and having simple and efficient constructs such as #caseOf: is very good IMHO. You are free to avoid them if your projects don't need it, and if you happen to need extra performance you can always build your own JIT, right? :) But please don't ban people who are willing to sacrifice a little readability for performance reasons. Thanks.
Best regards. Richo
-- www.tudorgirba.com
"Value is always contextual."
-- Best regards, Igor Stasenko AKA sig.
Le 13/02/2011 04:05, Ricardo Moran a écrit :
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere. no, it allows people to make their own opinion. interesting thread.
Now I can say that I would be more for getting rid of case of. thanks Alain
You got the process :) I like that we really discuss (because sometimes I'm wrong and I have no problem to change my mind :) I reminded me the discussion we got two yeras ago about number and nicolas convinced me that his approach was good about float (not been mathematical numbers). Stef On Feb 13, 2011, at 11:58 AM, Alain Plantec wrote:
Le 13/02/2011 04:05, Ricardo Moran a écrit :
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere. no, it allows people to make their own opinion. interesting thread.
Now I can say that I would be more for getting rid of case of.
thanks Alain
Of course discussion is good. But turning your position into a religion and blaming other parties ignorance is bad. That's what the discussion seemed to be heading (at least to me) and I just tried to avoid that. Maybe I'm just too new in this community (and smalltalk in general, for that matter) and this is how you solve your discussions, but I just don't like arguments such: "I don't like it and everyone using it should die" :) Now that more voices have joined the thread I think we are actually getting somewhere :) Cheers Richo On Sun, Feb 13, 2011 at 7:58 AM, Alain Plantec <alain.plantec@yahoo.com>wrote:
Le 13/02/2011 04:05, Ricardo Moran a écrit :
Ok, guys... I'm sorry to interrupt this polite discussion, but this is
taking nowhere.
no, it allows people to make their own opinion. interesting thread.
Now I can say that I would be more for getting rid of case of.
thanks Alain
Yes, I myself find the implementation hackish, but I wish I could see more pragmatic analysis based on exact usage of this message. The discussion isn't going forward, every one camping on its position. 1) Where is the message used ? 2) How would you refactor the senders ? 3) Does speed degrade ? 4) Does it matter ? For Pharo, I invite you to simply remove the compiler optimization, and run some benchmark. Then deprecate the message if you want (but you'll need a compatibility layer, notably for Cog). Nicolas 2011/2/13 Ricardo Moran <richi.moran@gmail.com>:
Of course discussion is good. But turning your position into a religion and blaming other parties ignorance is bad. That's what the discussion seemed to be heading (at least to me) and I just tried to avoid that. Maybe I'm just too new in this community (and smalltalk in general, for that matter) and this is how you solve your discussions, but I just don't like arguments such:Â "I don't like it and everyone using it should die" :) Now that more voices have joined the thread I think we are actually getting somewhere :) Cheers Richo
On Sun, Feb 13, 2011 at 7:58 AM, Alain Plantec <alain.plantec@yahoo.com> wrote:
Le 13/02/2011 04:05, Ricardo Moran a écrit :
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere.
no, it allows people to make their own opinion. interesting thread.
Now I can say that I would be more for getting rid of case of.
thanks Alain
Yes, I myself find the implementation hackish, but I wish I could see more pragmatic analysis based on exact usage of this message. The discussion isn't going forward, every one camping on its position. 1) Where is the message used ? 2) How would you refactor the senders ? 3) Does speed degrade ? 4) Does it matter ?
Yes I would like to know the answers :) And also can we get rid of the inlining. Does opal support it? I think that inlining just reserved to a really limited amount of case and caseOf: should not be part of it. We should have a simpler compiler and spending energy and time on real point. Stef
On 13 February 2011 17:44, Ricardo Moran <richi.moran@gmail.com> wrote:
Of course discussion is good. But turning your position into a religion and blaming other parties ignorance is bad. That's what the discussion seemed to be heading (at least to me) and I just tried to avoid that. Maybe I'm just too new in this community (and smalltalk in general, for that matter) and this is how you solve your discussions, but I just don't like arguments such:Â "I don't like it and everyone using it should die" :)
I meant a code which using it should die, not people of course. And of course this was not an argument at all. It was just to express my attitude to that :) And of course, i know Levente long enough to faulty considering him ignorant. Yes, i hate bad code.. But clearly not people :)
Now that more voices have joined the thread I think we are actually getting somewhere :) Cheers Richo
On Sun, Feb 13, 2011 at 7:58 AM, Alain Plantec <alain.plantec@yahoo.com> wrote:
Le 13/02/2011 04:05, Ricardo Moran a écrit :
Ok, guys... I'm sorry to interrupt this polite discussion, but this is taking nowhere.
no, it allows people to make their own opinion. interesting thread.
Now I can say that I would be more for getting rid of case of.
thanks Alain
-- Best regards, Igor Stasenko AKA sig.
On 13 February 2011 02:26, Levente Uzonyi <leves@elte.hu> wrote:
On Sun, 13 Feb 2011, Igor Stasenko wrote:
On 13 February 2011 00:59, Levente Uzonyi <leves@elte.hu> wrote:
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
We all know that it can be solved, but the solution won't be nicer at all, instead it will be a lot slower.
First, get rid of these integers in your code. Use symbolic names. And then for dispatching using parameter, there is a #peform: primitive.
The integers are from a binary stream, so I can't do much about it.
Oh yeah? Too bad for you then.
And everyone trying to implement a binary protocol efficiently.
So, then switch statement will be turned into:
self peform: (self decode: someInteger)
and this is how it should look like. And again, if you can avoid using integers at all, use symbols , so you don't have to decode/translate them. Just do #perform.
I thought that this is obvious for you.
What you wrote here is obvious, but not an answer to my question. What should #decode: do? Use #detect:? Or a dictionary? Maybe a binary search on an array? Or should it be a bunch of #ifTrue:ifFalse: conditionals? (I guess the separate class per integer idea is abandoned, but who knows.)
I don't care. You should encapsulate them into something , which has a meaning. Use bare numbers without any docs/comments/explanations to C.
Also note that #perform:with: is ~11x slower on Cog than sending a message. And a send is a lot slower (~5.5x IIRC) than a direct assignment. That's ~55x combined slowdown not counting the integer->selector matching.
Slower comparing to someone who will read your code and try to understand what it does. THAT WILL BE SLOWER and that is most precious resource we have, Â not the CPU time.
Is #caseOf: unreadable? No it's not. You just don't like it for some unknown reason. And you're not willing to tell what's your problem with it.
Please read the http://www.c2.com/cgi/wiki?PrematureOptimization :)
I know what's premature optimization. What I do differently than other people (including you) is: - if I can choose from different solutions for some problem, then I usually pick the one with the best expected performance if it has neglible other extra cost (complexity, readability, size, etc) compared to other solutions. E.g.: I usually write 1 to: 10 do: instead of (1 to: 10) do:, foo ifNotNil: [ ... ] instead of foo ifNotNilDo: [ ... ] or foo isNil ifFalse: [ ... ]), etc. - I optimize library code which is expected to be heavily used - I like to optimize code
Please read the Ian's paper about switch statement vs message sends.. You will discover something surprising for you.
Levente
Levente
-- Best regards, Igor Stasenko AKA sig.
-- Best regards, Igor Stasenko AKA sig.
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Please read the Ian's paper about switch statement vs message sends.. You will discover something surprising for you.
Link please? Levente
Levente
Levente
-- Best regards, Igor Stasenko AKA sig.
-- Best regards, Igor Stasenko AKA sig.
On 13 February 2011 02:58, Levente Uzonyi <leves@elte.hu> wrote:
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Please read the Ian's paper about switch statement vs message sends.. You will discover something surprising for you.
Link please?
Here: www.piumarta.com/pepsi/objmodel.pdf- ------------------- Lastly, we implemented the example presented in Section 2 of this paper: data structures suitable for a Lisp-like language. We implemented a âtraditionalâ length primitive using a switch on an integer tag to select the appropriate implementation amongst a set of possible case labels. This was compared with an implementation in which data was stored using our object model and the length primitive used send to invoke a method in the objects themselves.7 Both were run for one million iterations on forty objects, ten each of the four types that support the length operation. The results, with varying degrees of object model optimisations enabled, were: implementation time % of switch switch-based 503 ms 100.0% dynamic object-based 722 ms 69.7% + global cache 557 ms 90.3% + inline cache 243 ms 207.0% This shows that an , object-based implementation can perform at better than half the speed of a typical C implementation for a simple language primitive. With a global method cache (constant overhead, no matter how many method invocation sites exist) the performance is within 10% of optimised C. When the inline cache was enabled the performance was better than twice that of optimised C. ---------------------
Levente
-- Best regards, Igor Stasenko AKA sig.
On Sun, 13 Feb 2011, Igor Stasenko wrote:
On 13 February 2011 02:58, Levente Uzonyi <leves@elte.hu> wrote:
On Sun, 13 Feb 2011, Igor Stasenko wrote:
Please read the Ian's paper about switch statement vs message sends.. You will discover something surprising for you.
Link please?
That's C's switch statement (whose performance depends on the compiler, the structure of the cases, etc.) compared to inline caching? I don't see how is it relevant to #caseOf:? Levente
Here:
www.piumarta.com/pepsi/objmodel.pdf-
-------------------
Lastly, we implemented the example presented in Section 2 of this paper: data structures suitable for a Lisp-like language. We implemented a ËËtraditionalËË length primitive using a switch on an integer tag to select the appropriate implementation amongst a set of possible case labels. This was compared with an implementation in which data was stored using our object model and the length primitive used send to invoke a method in the objects themselves.7 Both were run for one million iterations on forty objects, ten each of the four types that support the length operation. The results, with varying degrees of object model optimisations enabled, were:
implementation time % of switch switch-based 503 ms 100.0% dynamic object-based 722 ms 69.7% + global cache 557 ms 90.3% + inline cache 243 ms 207.0%
This shows that an , object-based implementation can perform at better than half the speed of a typical C implementation for a simple language primitive. With a global method cache (constant overhead, no matter how many method invocation sites exist) the performance is within 10% of optimised C. When the inline cache was enabled the performance was better than twice that of optimised C. ---------------------
Levente
-- Best regards, Igor Stasenko AKA sig.
Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
You didn't answer the question though.
First, get rid of these integers in your code.
That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs? Steve
That's where I typically use a dictionary. Map the numbers to what is often a factory (a factory that reads from a stream being a common scenario) or sometimes closures. Create the map once on class initialization or once per "session" (or at least try not to build the map "every time"), and the result is reasonably efficient. It is really no different from what Smalltalk user interface frameworks do to dispatch messages to objects. Obviously, if the numbers are contiguous, one could use an array, but I find a dictionary convenient because there is no need to mess with offsets. ________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Stephen Taylor [stephen.taylor@bom.gov.au] Sent: Sunday, February 13, 2011 6:21 PM To: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
You didn't answer the question though.
First, get rid of these integers in your code.
That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs? Steve
On 14 February 2011 01:32, Schwab,Wilhelm K <bschwab@anest.ufl.edu> wrote:
That's where I typically use a dictionary. Â Map the numbers to what is often a factory (a factory that reads from a stream being a common scenario) or sometimes closures. Â Create the map once on class initialization or once per "session" (or at least try not to build the map "every time"), and the result is reasonably efficient. Â It is really no different from what Smalltalk user interface frameworks do to dispatch messages to objects. Â Obviously, if the numbers are contiguous, one could use an array, but I find a dictionary convenient because there is no need to mess with offsets.
Indeed.
________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Stephen Taylor [stephen.taylor@bom.gov.au] Sent: Sunday, February 13, 2011 6:21 PM To: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] could we agree to remove caseOf:  and   caseOf:otherwise:
Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
You didn't answer the question though.
Because it sounds rhetoric to me. How to deal with randomly put integers coming from outer source? If you're a software engineer, you should know it. :) But i can explain my vision: - first try to avoid dealing with them. So if you can control the protocol, use other ways of encoding actions/data. - organize these numbers (using dictionary or whatever), so they won't look like a random noise for people who first looking at your code. Put them into single place with documentation etc. And convert them to their symbolic representation as soon as possible. - never use bare numbers as a labels which influencing a control flow (like in switch statement, branches etc). Instead, use their symbolic names. This will prevent many many many errors, typos and mistakes and make your code more documented.
First, get rid of these integers in your code.
That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs?
       Steve
-- Best regards, Igor Stasenko AKA sig.
I agree with both Igor and Levente. Uses of caseOf: is often times solvable in more "elegant" ways. Though, I think in f.ex. HandMorph>>#processEvents and UTF8TextConverter>>nextFromStream:, it would actually *improve* readability to use it. Got any good refactoring to symbolics for those two, Igor? ;) Cheers, Henry -1 for removal/deprecation from me (from the system, not necessarily as special cases for the compiler) -- View this message in context: http://forum.world.st/could-we-agree-to-remove-caseOf-and-caseOf-otherwise-t... Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
On 14 February 2011 15:57, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
I agree with both Igor and Levente.
Uses of caseOf: is often times solvable in more "elegant" ways.
Though, I think in f.ex. HandMorph>>#processEvents  and UTF8TextConverter>>nextFromStream:, it would actually *improve* readability to use it.
Got any good refactoring to symbolics for those two, Igor? ;)
Yes, i having the code somewhere for translating evtBuf to nice events. So the HandMorph>>processEvents then will be: Sensor nextEvent dispatchOn: self at some day :-) As for UTF8, the caseOf is not clearly applicable, because it using ranged comparison, so you can't dispatch using the table: nextUTF8Char | value1 value2 value3 value4 | (value1 := self nextByte) ifNil: [^ self endOfStreamAction value]. value1 <= 127 ifTrue: [ "1-byte character" ^ Character value: value1 ]. "at least 2-byte character" (value2 := self nextByte) ifNil: [^self errorMalformedInput]. value1 <= 2r11011111 ifTrue: [ ^ Unicode charFromUnicode: ((value1 bitAnd: 31) bitShift: 6) + (value2 bitAnd: 63). ]. "at least 3-byte character" (value3 := self nextByte) ifNil: [^self errorMalformedInput]. (value1 <= 2r11101111) ifTrue: [ ^ Unicode charFromUnicode: ((value1 bitAnd: 15) bitShift: 12) + ((value2 bitAnd: 63) bitShift: 6) + (value3 bitAnd: 63). ]. "4-byte character" (value1 <= 2r11110111) ifTrue: [ (value4 := self nextByte) ifNil: [^self errorMalformedInput]. ^ Unicode charFromUnicode: ((value1 bitAnd: 16r7) bitShift: 18) + ((value2 bitAnd: 63) bitShift: 12) + ((value3 bitAnd: 63) bitShift: 6) + (value4 bitAnd: 63). ]. ^self errorMalformedInput
Cheers, Henry
-1 for removal/deprecation from me (from the system, not necessarily as special cases for the compiler) -- View this message in context: http://forum.world.st/could-we-agree-to-remove-caseOf-and-caseOf-otherwise-t... Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko AKA sig.
Igor Stasenko wrote:
On 14 February 2011 01:32, Schwab,Wilhelm K <bschwab@anest.ufl.edu> wrote:
That's where I typically use a dictionary.
Indeed.
Yes - sensible answer from Wilhelm Schwab.
You didn't answer the question though.
Because it sounds rhetoric to me. How to deal with randomly put integers coming from outer source? If you're a software engineer, you should know it. :)
Indeed. Case construct is sometimes an appropriate way.
- first try to avoid dealing with them. So if you can control the protocol, use other ways of encoding actions/data.
Yes, but the point is that one does not always have full control of ones environment. Of course it would be nice it to have sensible input data. It would be nice to have a pony with wings too.
- organize these numbers (using dictionary or whatever), so they won't look like a random noise for people who first looking at your code. Put them into single place with documentation etc.
I do like the dictionary approach and sometimes do that. Other times I wonder if I've made the world that much of a better place by loading the logic into a dictionary rather than leaving it out in the code where anyone can see it. It depends on the number of symbols. I'm going to leave it here, as I don't want to find myself in the position of the last and loudest advocate of case statements. I don't think they're that good an idea in most circumstances, but I do think they're reasonable enough sometimes. Steve
Hi, I'm sorry to interrupt that discussion, but I read all the messages about that subject since you started to discuss it and I really would like to understand a thing: Why does the case structure seem to be so bad in Smalltalk? I hope some of you could explain me :) Adrien.
On 14 February 2011 23:33, Adrien BARREAU <abarreau.dev@live.fr> wrote:
Hi,
I'm sorry to interrupt that discussion, but I read all the messages about that subject since you started to discuss it and I really would like to understand a thing: Why does the case structure seem to be so bad in Smalltalk?
I hope some of you could explain me :)
Because you can do such kind of dispatching using messages.
Adrien.
-- Best regards, Igor Stasenko AKA sig.
you should follow my lecture if one day they let me do it at Lille. Why Boolean operations are not using ifTrue:ifFalse: everywhere....? I spent two hours explaining that point. Stef On Feb 14, 2011, at 11:33 PM, Adrien BARREAU wrote:
Hi,
I'm sorry to interrupt that discussion, but I read all the messages about that subject since you started to discuss it and I really would like to understand a thing: Why does the case structure seem to be so bad in Smalltalk?
I hope some of you could explain me :)
Adrien.
Adrien, Case (a.k.a "switch") constructs are not "so bad in Smalltalk" only, they are considered bad OO practice and it is tabled in the "The Object-Orientation Abuse" code smell when refactoring. there is an abundant literature about it that you can find online, so I'll refrain to make this post to long. If you folks think it is worth, we can open a different thread... -- Cesar Rabak Em 14/02/2011 20:33, Adrien BARREAU < abarreau.dev@live.fr > escreveu: Hi, I'm sorry to interrupt that discussion, but I read all the messages about that subject since you started to discuss it and I really would like to understand a thing: Why does the case structure seem to be so bad in Smalltalk? I hope some of you could explain me :) Adrien.
This solution has the disadvantages of caseOf: solution, namely a non OO approach requiring maintenance in several places in the code, and the disadvantages of having less performance on the speed metric. I think it is capricious to stick to it, except if the Smalltalk flavour you're using does not offer the caseOf: construct. my 0.0199999... -- Cesar Rabak Em 13/02/2011 22:32, Schwab,Wilhelm K < bschwab@anest.ufl.edu > escreveu: That's where I typically use a dictionary. Map the numbers to what is often a factory (a factory that reads from a stream being a common scenario) or sometimes closures. Create the map once on class initialization or once per "session" (or at least try not to build the map "every time"), and the result is reasonably efficient. It is really no different from what Smalltalk user interface frameworks do to dispatch messages to objects. Obviously, if the numbers are contiguous, one could use an array, but I find a dictionary convenient because there is no need to mess with offsets. ________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Stephen Taylor [stephen.taylor@bom.gov.au] Sent: Sunday, February 13, 2011 6:21 PM To: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
You didn't answer the question though.
First, get rid of these integers in your code.
That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs? Steve
Em 13/02/2011 21:21, Stephen Taylor < stephen.taylor@bom.gov.au > escreveu: Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
Igor's attitude, which I'll take as sample of a school of thought is dangerously similar to the one which in name of keeping certain aspects of Smalltalk "pure" or near to the origins has made its acceptance fall as the other aspects of the technology (OO, WIMP, etc.), made their way into other languages/platforms/technologies.
You didn't answer the question though.
And then this: to the first concrete example, no complete answer comes out which we could check if the code construct is indeed only a syntactic sugar, or deserves incorporation in the toolset of the language...
First, get rid of these integers in your code. That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs?
FWIW, this kind of need, namely having to take alternate actions due different integer codes is pretty common when interfacing with industrial boards, a lot of protocols use this as well and most of them are already in use, some even have international standards. So the answer "redesign your world to fit our world-view" does not cut in... Also, another argument I've seen in this thread which is pretty commonplace w.r.t. performance must be extirpated in our discourse: "the performance x to y slower than <baseline implementation> is very good considering {dynamic} languages (or similar statement)". Performance counts! One of the reasons we're working in Pharo is to bring its performance on par with competitive technologies. We're doing things to take out 'cruft', some to make the abstractions more elegant, but some are pragmatic which require depart of breaking 'pure' Smalltalk OO way of thinking. -- Cesar Rabak
Steve
I am not completely certain who is on which side here anymore, other than #caseOf: is at the center of it. I think I saw Eliot say that Cog uses it; if I got that right, it's a pretty compelling reason to keep it in the image. Doing that, either for Cog's benefit, or even just for the convenience of a subset of users does not necessarily imply that Pharo itself needs to use the message. That is about the limit of what I can offer in the form of guidance, and it is really more of a question: could Pharo be changed to ignore the message, and then keep it in the image for Cog and other users? Maybe that is too idealistic, or just plain naive :) Mapping integers from the outside world to objects and/or behavior is something that I do a lot. I have to more or less agree with Sig; case statements as such generally point to room for a design to better exploit messaging. There are indeed scenarios (especially if not exclusively in external interfacing) that call for mapping numbers to actions. I have had great results with dictionaries for that purpose, but I am not trying to squeeze every last byte code per second out of a portable VM. There have been situations in which Smalltalkers have climbed the ivory tower and looked with contempt on things that make the world work. I am not convinced that is happening here. ________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of csrabak@bol.com.br [csrabak@bol.com.br] Sent: Tuesday, February 15, 2011 1:23 PM To: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: Em 13/02/2011 21:21, Stephen Taylor < stephen.taylor@bom.gov.au > escreveu: Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
Igor's attitude, which I'll take as sample of a school of thought is dangerously similar to the one which in name of keeping certain aspects of Smalltalk "pure" or near to the origins has made its acceptance fall as the other aspects of the technology (OO, WIMP, etc.), made their way into other languages/platforms/technologies.
You didn't answer the question though.
And then this: to the first concrete example, no complete answer comes out which we could check if the code construct is indeed only a syntactic sugar, or deserves incorporation in the toolset of the language...
First, get rid of these integers in your code. That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs?
FWIW, this kind of need, namely having to take alternate actions due different integer codes is pretty common when interfacing with industrial boards, a lot of protocols use this as well and most of them are already in use, some even have international standards. So the answer "redesign your world to fit our world-view" does not cut in... Also, another argument I've seen in this thread which is pretty commonplace w.r.t. performance must be extirpated in our discourse: "the performance x to y slower than <baseline implementation> is very good considering {dynamic} languages (or similar statement)". Performance counts! One of the reasons we're working in Pharo is to bring its performance on par with competitive technologies. We're doing things to take out 'cruft', some to make the abstractions more elegant, but some are pragmatic which require depart of breaking 'pure' Smalltalk OO way of thinking. -- Cesar Rabak
Steve
Em 15-02-2011 16:55, Schwab,Wilhelm K escreveu:
I am not completely certain who is on which side here anymore, other than #caseOf: is at the center of it. I think I saw Eliot say that Cog uses it; if I got that right, it's a pretty compelling reason to keep it in the image. Doing that, either for Cog's benefit, or even just for the convenience of a subset of users does not necessarily imply that Pharo itself needs to use the message. That is about the limit of what I can offer in the form of guidance, and it is really more of a question: could Pharo be changed to ignore the message, and then keep it in the image for Cog and other users? Maybe that is too idealistic, or just plain naive :)
Mapping integers from the outside world to objects and/or behavior is something that I do a lot. I have to more or less agree with Sig; case statements as such generally point to room for a design to better exploit messaging. There are indeed scenarios (especially if not exclusively in external interfacing) that call for mapping numbers to actions. I have had great results with dictionaries for that purpose, but I am not trying to squeeze every last byte code per second out of a portable VM. Yeah, implementations using dictionaries are quite elegant. And they're not usually expensive in terms of processing. Anyways, when processing external input, IO is usually much slower than relating a numeric value to a symbol & then performing an action...
There are lots of alternatives to performing a "caseOf:" thing, so I just don't see things as a question of "smalltalk purity".
There have been situations in which Smalltalkers have climbed the ivory tower and looked with contempt on things that make the world work. I am not convinced that is happening here.
On 15 February 2011 19:23, <csrabak@bol.com.br> wrote:
Em 13/02/2011 21:21, Stephen Taylor < stephen.taylor@bom.gov.au > escreveu: Igor Stasenko wrote:
You  have some  integers: 0  83 67  77  68 72  80 112  113 87  70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
Igor's attitude, which I'll take as sample of a school of thought is dangerously similar to the  one which in name of keeping certain aspects of Smalltalk "pure" or near to the origins has made its acceptance  fall as the other aspects of the technology (OO, WIMP, etc.), made their way into other languages/platforms/technologies.
I am not opposed to innovations or cross-breeding techs. My purism lies on simple principle: KISS. If something could be made simpler without losing key features then it should done.
 You didn't answer the question though.
And then this: to the first concrete example, no complete answer comes out which we could check if the code construct is indeed only a syntactic sugar, or deserves incorporation in the toolset of the language...
I don't see a need of explaining how to interpret a simple translation without using caseOf: statement.
 > First, get rid of these integers in your code.  That's the killer  - yes, we can usually  design around cases where we'd use case constructs (though I'm not convinced they're the spawn of  the devil)  but what  about cases  where we're  interfacing with external data sources and we  don't get to redesign the whole system to suit our needs?
FWIW, this kind of need, namely having to take alternate actions due different integer codes is pretty common when interfacing with industrial boards, a lot of protocols use this as well and most of them are already in use, some even have international standards.
And i suspect that all these standards are properly documented, and each signal/number having its description, so you can represent them by names, not by numbers.
So the answer "redesign your world to fit our world-view" does not cut in...
I'm not asking you to redesign C world to fit smalltalk view. Use each tool what it made for. What i asking is to not use a microscope for hammering nails. Hammer is much better tool for that.
Also, another argument I've seen in this thread which is pretty commonplace w.r.t. performance must be extirpated in our discourse: "the performance x to y slower than <baseline implementation> is very good considering {dynamic} languages (or similar statement)".
Performance counts!
Sure. At some point if you train long enough you can hammer nail using microscope much faster than using hammer. But that still doesn't means that you doing it right :)
One of the reasons we're working in Pharo is to bring its performance on par with competitive technologies. Â We're doing things to take out 'cruft', some to make the abstractions more elegant, but some are pragmatic which require depart of breaking 'pure' Smalltalk OO way of thinking.
-- Cesar Rabak
 Steve
-- Best regards, Igor Stasenko AKA sig.
Em 15/02/2011 17:03, Igor Stasenko < siguctua@gmail.com > escreveu: On 15 February 2011 19:23, wrote:
Em 13/02/2011 21:21, Stephen Taylor < stephen.taylor@bom.gov.au > escreveu: Igor Stasenko wrote:
You have some integers: 0 83 67 77 68 72 80 112 113 87 70 82. When a variable's value is equal to any of these...
Don't try to convince me that there are sort of problems which can be solved only by using case statement :)
Igor's attitude, which I'll take as sample of a school of thought is dangerously similar to the one which in name of keeping certain aspects of Smalltalk "pure" or near to the origins has made its acceptance fall as the other aspects of the technology (OO, WIMP, etc.), made their way into other languages/platforms/technologies.
I am not opposed to innovations or cross-breeding techs. My purism lies on simple principle: KISS. If something could be made simpler without losing key features then it should done.
Your KISS principle has to come at odds with another one, which was the reason why the construct was put in place: performance. This is called engineering, it is the art of trade off.
You didn't answer the question though. And then this: to the first concrete example, no complete answer comes out which we could check if the code construct is indeed only a syntactic sugar, or deserves incorporation in the toolset of the language... I don't see a need of explaining how to interpret a simple translation without using caseOf: statement.
You don't, because you already decided that what it is at stake doesn't matter for Pharo. I'm just trying to recap here: the construct is not here to mud the purity of a beatiful OO language nor be incentive to bad code smells. It has been put to solve a particular problem in a very specific part of the system.
First, get rid of these integers in your code. That's the killer - yes, we can usually design around cases where we'd use case constructs (though I'm not convinced they're the spawn of the devil) but what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs? FWIW, this kind of need, namely having to take alternate actions due different integer codes is pretty common when interfacing with industrial boards, a lot of protocols use this as well and most of them are already in use, some even have international standards. And i suspect that all these standards are properly documented, and each signal/number having its description, so you can represent them by names, not by numbers.
I may lost something, but how will you convert the numbers in names to start with?
So the answer "redesign your world to fit our world-view" does not cut in...
I'm not asking you to redesign C world to fit smalltalk view. Use each tool what it made for. What i asking is to not use a microscope for hammering nails. Hammer is much better tool for that.
This statement is called in Informal Logic "the Fallacy of the False Analogy".
Also, another argument I've seen in this thread which is pretty commonplace w.r.t. performance must be extirpated in our discourse: "the performance x to y slower than is very good considering {dynamic} languages (or similar statement)". Performance counts! Sure. At some point if you train long enough you can hammer nail using microscope much faster than using hammer. But that still doesn't means that you doing it right :)
As I already pointed out, your base reasoning is false, this is consequentially /non sequitur/.
On 15 February 2011 20:38, <csrabak@bol.com.br> wrote:
Em 15/02/2011 17:03, Igor Stasenko < siguctua@gmail.com > escreveu: On 15 February 2011 19:23, wrote:
Em 13/02/2011 21:21, Â Stephen Taylor < stephen.taylor@bom.gov.au > escreveu: Igor Stasenko wrote:
You have  some integers: 0  83 67  77 68 72  80 112 113  87 70 82. When a variable's value is equal to any of these...
Don't try to convince me  that there are sort of problems which can be solved only by using case statement :)
Igor's attitude, which I'll take  as sample of a school of thought is dangerously similar to the one which in name of keeping certain aspects of  Smalltalk "pure" or near  to the origins  has made its acceptance fall as the other  aspects of the technology (OO, WIMP, etc.), made their way into other languages/platforms/technologies.
 I am not opposed to innovations or cross-breeding techs.  My purism lies on simple principle: KISS.  If something could be made simpler without losing key features then it should done.
Your KISS principle has to come at odds with another one, which was the reason why the construct was put in place: performance.
This is called engineering, it is the art of trade off.
So we will never agree here. We are different and having different view on it.
You didn't answer the question though. And then this:  to the first concrete example,  no complete answer comes out  which we  could check if  the code construct  is indeed only a  syntactic sugar, or deserves incorporation  in the toolset of the language...  I don't  see  a need  of  explaining how  to  interpret a  simple translation without using caseOf: statement.
You don't, because you already decided that what it is at stake doesn't matter for Pharo.
I'm just trying to recap here: the construct is not here to mud the purity of a beatiful OO language nor be incentive to bad code smells. Â It has been put to solve a particular problem in a very specific part of the system.
nope. I suspecting that it is there to mimic C switch statement.. because some people, when discovering something new, often trying to bring everything they knew/used before. Even if it doesn't fit.. But they are loving they old toys too much for just leaving them behind. Or they faulty thinking that some cool technique that served well for them in one case, will serve as well everywhere , not depending on environment. Such people are not trying to adapt themselves to new environment, instead they trying to adapt environment for themselves.
 > First,  get rid  of these integers  in your code.  That's the  killer - yes, we can usually design around cases where we'd use  case constructs (though  I'm not convinced  they're the spawn of the devil) but  what about cases where we're interfacing with external data sources and we don't get to redesign the whole system to suit our needs? FWIW, this kind  of need, namely having to  take alternate actions due different integer codes is pretty common when interfacing with industrial boards, a lot of protocols use this as well and most of them are already in use, some even have international standards.  And i suspect that all these standards are properly documented, and each signal/number having its description, so you can represent them by names, not by numbers.
I may lost something, but how will you convert the numbers in names to start with?
name := numbers at: number. where numbers is dictionary/table/whatever which contains translation. Even C code using defines to represent numbers by names. So, what you prefer to see in code. This: switch (response) case 1: .. case 2: .. case 3: .. or this: #define Yes 1 #define No 2 #define NotSure 3 switch (response) case Yes: .. case No: .. case NotSure: ... and what code to your thinking having better chance to evolve and/or live longer than its original author?
So the answer "redesign your world to fit our world-view" does not cut in...
 I'm not asking  you to redesign C world to  fit smalltalk view. Use each  tool  what it  made  for.  What i  asking  is  to  not use  a microscope for hammering nails. Hammer is much better tool for that.
This statement is called in Informal Logic "the Fallacy of the False Analogy".
You may call it however you like. Just don't convince me that it is a good idea to come to lab and use microscope for hammering nails. Because its shape somewhat reminds the hammer you using in garage.
Also, another  argument I've seen  in this thread which  is pretty commonplace w.r.t. performance must be extirpated in our discourse: "the  performance x  to  y  slower than  is  very good  considering {dynamic} languages (or similar statement)". Performance counts!  Sure. At  some point if you  train long enough you  can hammer nail using  microscope much  faster  than using  hammer.  But that  still doesn't means that you doing it right :)
As I already pointed out, your base reasoning is false, this is consequentially /non sequitur/.
-- Best regards, Igor Stasenko AKA sig.
On 12 Feb 2011, at 18:41, Levente Uzonyi wrote:
~27x slowdown in this case.
I personally never heard of #caseOf:otherwise ! It feels like a hack that is not often needed. If after writing correct code you need to optimize integer/byte handling, there are many solutions, check any book on algorithms, most of them are using table dispatch. Another problem in your benchmark is that you keep the creation of the dynamic array inside the code to measure, while in the compiler primitive case it is of course compiled away, that alone makes a huge difference: (timings on my machine) [ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '8,920,000 per second.' [ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '70,600 per second.' | actions | actions := { [ $a ]. [ $b ]. [ $c ]. [ $d ]. [ $e ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. }. [ 1 to: 10 do: [ :each | (actions at: each) value ] ] bench. '3,230,000 per second.' | letters | letters := 'abcdexxxxx'. [ 1 to: 10 do: [ :each | letters at: each ] ] bench. '8,930,000 per second.' If other Smalltalks can live without it, so can we. Sven
On Sun, 13 Feb 2011, Sven Van Caekenberghe wrote:
On 12 Feb 2011, at 18:41, Levente Uzonyi wrote:
~27x slowdown in this case.
I personally never heard of #caseOf:otherwise !
It feels like a hack that is not often needed.
You don't need it often, but it's sometimes useful.
If after writing correct code you need to optimize integer/byte handling, there are many solutions, check any book on algorithms, most of them are using table dispatch.
The blocks of #caseOf: are not just boilerplate code, you can evaluate any expression there. It's cumbersome to do that with table based dispatch.
Another problem in your benchmark is that you keep the creation of the dynamic array inside the code to measure, while in the compiler primitive case it is of course compiled away, that alone makes a huge difference:
It's not a problem, it's intentional. See the mail that I replied to. Levente
(timings on my machine)
[ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '8,920,000 per second.'
[ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '70,600 per second.'
| actions | actions := { [ $a ]. [ $b ]. [ $c ]. [ $d ]. [ $e ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. }. [ 1 to: 10 do: [ :each | (actions at: each) value ] ] bench. '3,230,000 per second.'
| letters | letters := 'abcdexxxxx'. [ 1 to: 10 do: [ :each | letters at: each ] ] bench. '8,930,000 per second.'
If other Smalltalks can live without it, so can we.
Sven
Let's get to the point here... Most people will tell you it's an awful "beast" that doesn't belong to the OO and Smalltalk world. If I *love* case statements and I absolutely need them, I can code in C. If I *love* case statements and I absolutely need them, nothing prevents me from adding them to the image as my own-superoptimized extension. You'll always find something, someone, somewhere who could argue about the need for such a thing but in reality, I guess this method has always bugged most Smalltalkers... It's ugly, not OO, not good style and good practice, not essential and not needed by 99% of the people here (and if it's sooooooooooo needed, how do you explain that all other Smalltalk vendors haven't implement it as part of their core libraries ?). So let's vote (you won't argue against democracy, won't you?!) for the removal of #caseOf:otherwise: and let's move forward onto more important business. On a less serious note, let's all remember what Spock said: "Were I to invoke logic, however, logic clearly dictates that the needs of the many outweigh the needs of the few" Let's remove this thing! +1 P.S. Performance-wise, if you always need "optimized" code, you can always rely on primitives & plugins... Let's not go performance-frenzy here! We don't want to end up in an environment where all the code is unreadable... Clarity & simplicity are good, not evil in Smalltalk! ----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein) ________________________________ From: Levente Uzonyi <leves@elte.hu> To: Pharo-project@lists.gforge.inria.fr Sent: Sun, February 13, 2011 8:50:53 AM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: On Sun, 13 Feb 2011, Sven Van Caekenberghe wrote:
On 12 Feb 2011, at 18:41, Levente Uzonyi wrote:
~27x slowdown in this case.
I personally never heard of #caseOf:otherwise !
It feels like a hack that is not often needed.
You don't need it often, but it's sometimes useful.
If after writing correct code you need to optimize integer/byte handling, there are many solutions, check any book on algorithms, most of them are using table dispatch.
The blocks of #caseOf: are not just boilerplate code, you can evaluate any expression there. It's cumbersome to do that with table based dispatch.
Another problem in your benchmark is that you keep the creation of the dynamic array inside the code to measure, while in the compiler primitive case it is of course compiled away, that alone makes a huge difference:
It's not a problem, it's intentional. See the mail that I replied to. Levente
(timings on my machine)
[ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '8,920,000 per second.'
[ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '70,600 per second.'
| actions | actions := { [ $a ]. [ $b ]. [ $c ]. [ $d ]. [ $e ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. }. [ 1 to: 10 do: [ :each | (actions at: each) value ] ] bench. '3,230,000 per second.'
| letters | letters := 'abcdexxxxx'. [ 1 to: 10 do: [ :each | letters at: each ] ] bench. '8,930,000 per second.'
If other Smalltalks can live without it, so can we.
Sven
Read the Federalist Papers and Bastiat's "The Law," and then we can talk about democracy, one illustration of which is three wolves and a sheep voting on the dinner menu. In its raw form, yes, I argue against democracy, aka mob rule. However, we are not talking about taking someone's life, liberty or property here: this is software, and one can always retain #caseOf: in any image. However, a vote seems reasonable. I would be just as willing to accept the ruling of the benign dictators. A switch often suggests inadequate reification (aka direct polymorphism or double dispatch might be in order), but I sometimes resort to a dictionary as a quick way to map numbers or strings to actions. Since landing in Pharo, I have been using the modified stream protocol I developed in response to default actions, which I consider to be a disaster in the making. Others are less worried about it. It is fairly easy to have some code that one loads into an image. I do it for streams, others can do it for case statements. The above said, one thing I don't like is "you can't do that because I think its' ugly." Perhaps a compromise for Stef to consider is to clean the uses of the method so it is not used in the image (effectively removing it), but leave it in place for those who want to use it their own code?? Bill ________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Benoit St-Jean [bstjean@yahoo.com] Sent: Sunday, February 13, 2011 9:43 AM To: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: Let's get to the point here... Most people will tell you it's an awful "beast" that doesn't belong to the OO and Smalltalk world. If I *love* case statements and I absolutely need them, I can code in C. If I *love* case statements and I absolutely need them, nothing prevents me from adding them to the image as my own-superoptimized extension. You'll always find something, someone, somewhere who could argue about the need for such a thing but in reality, I guess this method has always bugged most Smalltalkers... It's ugly, not OO, not good style and good practice, not essential and not needed by 99% of the people here (and if it's sooooooooooo needed, how do you explain that all other Smalltalk vendors haven't implement it as part of their core libraries ?). So let's vote (you won't argue against democracy, won't you?!) for the removal of #caseOf:otherwise: and let's move forward onto more important business. On a less serious note, let's all remember what Spock said: "Were I to invoke logic, however, logic clearly dictates that the needs of the many outweigh the needs of the few" Let's remove this thing! +1 P.S. Performance-wise, if you always need "optimized" code, you can always rely on primitives & plugins... Let's not go performance-frenzy here! We don't want to end up in an environment where all the code is unreadable... Clarity & simplicity are good, not evil in Smalltalk! ----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein) ________________________________ From: Levente Uzonyi <leves@elte.hu> To: Pharo-project@lists.gforge.inria.fr Sent: Sun, February 13, 2011 8:50:53 AM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: On Sun, 13 Feb 2011, Sven Van Caekenberghe wrote:
On 12 Feb 2011, at 18:41, Levente Uzonyi wrote:
~27x slowdown in this case.
I personally never heard of #caseOf:otherwise !
It feels like a hack that is not often needed.
You don't need it often, but it's sometimes useful.
If after writing correct code you need to optimize integer/byte handling, there are many solutions, check any book on algorithms, most of them are using table dispatch.
The blocks of #caseOf: are not just boilerplate code, you can evaluate any expression there. It's cumbersome to do that with table based dispatch.
Another problem in your benchmark is that you keep the creation of the dynamic array inside the code to measure, while in the compiler primitive case it is of course compiled away, that alone makes a huge difference:
It's not a problem, it's intentional. See the mail that I replied to. Levente
(timings on my machine)
[ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '8,920,000 per second.'
[ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '70,600 per second.'
| actions | actions := { [ $a ]. [ $b ]. [ $c ]. [ $d ]. [ $e ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. }. [ 1 to: 10 do: [ :each | (actions at: each) value ] ] bench. '3,230,000 per second.'
| letters | letters := 'abcdexxxxx'. [ 1 to: 10 do: [ :each | letters at: each ] ] bench. '8,930,000 per second.'
If other Smalltalks can live without it, so can we.
Sven
I mostly agree with you on all points Bill.. It's just that usually, "ugliness" in Smalltalk, is a symptom of bad design or at least that something could be refactored a little bit more... In all the years and all the Smalltalk implementations, why did no one ever implemented Number arithmetic operations using case statements (or case style) and used double dispatch instead ?? I guess there are many other ways this could have been implemented more effectively (performance-wise) but simplicity & clarity seem to have won. Simplicity & clarity have their merits. It's no wonder, a few years ago, there was a Smalltalk implementation that allowed "assembly code" inside Smalltalk code but this feature never got popular even though "it could have been extremely fast". What a real mess. Probably really efficient & fast but was a mess from a readability & maintenance standpoint... I'm just really skeptical about always presenting speed as the main argument when it comes to Smalltalk & the way to code and implement things. It's like having a Cessna and trying to make it fly like the space shuttle. It wasn't designed for that. Yes we could add boosters, yes we could extend the wings, yes we could change the engine, yes we could patch this, yes we could do that, etc. If I want to go to the moon, I'll use the Space Shuttle but in the meantime, I must not forget I'm piloting and using a Cessna. This #caseOf:otherwise: painfully reminds me of a coding horror I saw years ago... The programmer told us he was never sure of the receiver (a few possible classes only) and had to rely on a "very useful and flexible" method called #ifTrue:ifFalse:ifNil:ifEmpty:otherwise: .Obviously, you can only imagine the rest of the "logic" involved where this method was called... Double dispatching would have been so simpler and more elegant. It felt like doing BASIC a class browser ! I'm not against change when needed. I'm not against suggestions. I'm not against speed improvements. But I'm not for speed at all costs, especially code readability. If we want speed, it's in the VM we have to implement it. Cincom rarely relied on ugly Smalltalk code implementations to make VW faster. They pushed the VM. Not the Collection hierrachy, not the Number hierarchy, not the Stream, etc. Besides, performance arguments is a slippery slope. What about memory consumption? Which road should we take ? It's fast but it instantiates 10 million objects or it's small and used 3Ks of memory but runs 5 seconds slower? There's always another side to what "efficiency" means to everyone. My 2 cents! :) ----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein) ________________________________ From: "Schwab,Wilhelm K" <bschwab@anest.ufl.edu> To: "Pharo-project@lists.gforge.inria.fr" <Pharo-project@lists.gforge.inria.fr> Sent: Sun, February 13, 2011 12:13:41 PM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: Read the Federalist Papers and Bastiat's "The Law," and then we can talk about democracy, one illustration of which is three wolves and a sheep voting on the dinner menu. In its raw form, yes, I argue against democracy, aka mob rule. However, we are not talking about taking someone's life, liberty or property here: this is software, and one can always retain #caseOf: in any image. However, a vote seems reasonable. I would be just as willing to accept the ruling of the benign dictators. A switch often suggests inadequate reification (aka direct polymorphism or double dispatch might be in order), but I sometimes resort to a dictionary as a quick way to map numbers or strings to actions. Since landing in Pharo, I have been using the modified stream protocol I developed in response to default actions, which I consider to be a disaster in the making. Others are less worried about it. It is fairly easy to have some code that one loads into an image. I do it for streams, others can do it for case statements. The above said, one thing I don't like is "you can't do that because I think its' ugly." Perhaps a compromise for Stef to consider is to clean the uses of the method so it is not used in the image (effectively removing it), but leave it in place for those who want to use it their own code?? Bill ________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Benoit St-Jean [bstjean@yahoo.com] Sent: Sunday, February 13, 2011 9:43 AM To: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: Let's get to the point here... Most people will tell you it's an awful "beast" that doesn't belong to the OO and Smalltalk world. If I *love* case statements and I absolutely need them, I can code in C. If I *love* case statements and I absolutely need them, nothing prevents me from adding them to the image as my own-superoptimized extension. You'll always find something, someone, somewhere who could argue about the need for such a thing but in reality, I guess this method has always bugged most Smalltalkers... It's ugly, not OO, not good style and good practice, not essential and not needed by 99% of the people here (and if it's sooooooooooo needed, how do you explain that all other Smalltalk vendors haven't implement it as part of their core libraries ?). So let's vote (you won't argue against democracy, won't you?!) for the removal of #caseOf:otherwise: and let's move forward onto more important business. On a less serious note, let's all remember what Spock said: "Were I to invoke logic, however, logic clearly dictates that the needs of the many outweigh the needs of the few" Let's remove this thing! +1 P.S. Performance-wise, if you always need "optimized" code, you can always rely on primitives & plugins... Let's not go performance-frenzy here! We don't want to end up in an environment where all the code is unreadable... Clarity & simplicity are good, not evil in Smalltalk! ----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein) ________________________________ From: Levente Uzonyi <leves@elte.hu> To: Pharo-project@lists.gforge.inria.fr Sent: Sun, February 13, 2011 8:50:53 AM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: On Sun, 13 Feb 2011, Sven Van Caekenberghe wrote:
On 12 Feb 2011, at 18:41, Levente Uzonyi wrote:
~27x slowdown in this case.
I personally never heard of #caseOf:otherwise !
It feels like a hack that is not often needed.
You don't need it often, but it's sometimes useful.
If after writing correct code you need to optimize integer/byte handling, there are many solutions, check any book on algorithms, most of them are using table dispatch.
The blocks of #caseOf: are not just boilerplate code, you can evaluate any expression there. It's cumbersome to do that with table based dispatch.
Another problem in your benchmark is that you keep the creation of the dynamic array inside the code to measure, while in the compiler primitive case it is of course compiled away, that alone makes a huge difference:
It's not a problem, it's intentional. See the mail that I replied to. Levente
(timings on my machine)
[ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '8,920,000 per second.'
[ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '70,600 per second.'
| actions | actions := { [ $a ]. [ $b ]. [ $c ]. [ $d ]. [ $e ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. [ $x ]. }. [ 1 to: 10 do: [ :each | (actions at: each) value ] ] bench. '3,230,000 per second.'
| letters | letters := 'abcdexxxxx'. [ 1 to: 10 do: [ :each | letters at: each ] ] bench. '8,930,000 per second.'
If other Smalltalks can live without it, so can we.
Sven
+1 to your arguments, Benoit! Janko On 13. 02. 2011 19:29, Benoit St-Jean wrote:
I mostly agree with you on all points Bill.. It's just that usually, "ugliness" in Smalltalk, is a symptom of bad design or at least that something could be refactored a little bit more... In all the years and all the Smalltalk implementations, why did no one ever implemented Number arithmetic operations using case statements (or case style) and used double dispatch instead ?? I guess there are many other ways this could have been implemented more effectively (performance-wise) but simplicity & clarity seem to have won. Simplicity & clarity have their merits. It's no wonder, a few years ago, there was a Smalltalk implementation that allowed "assembly code" inside Smalltalk code but this feature never got popular even though "it could have been extremely fast". What a real mess. Probably really efficient & fast but was a mess from a readability & maintenance standpoint...
I'm just really skeptical about always presenting speed as the main argument when it comes to Smalltalk & the way to code and implement things. It's like having a Cessna and trying to make it fly like the space shuttle. It wasn't designed for that. Yes we could add boosters, yes we could extend the wings, yes we could change the engine, yes we could patch this, yes we could do that, etc. If I want to go to the moon, I'll use the Space Shuttle but in the meantime, I must not forget I'm piloting and using a Cessna.
This #caseOf:otherwise: painfully reminds me of a coding horror I saw years ago... The programmer told us he was never sure of the receiver (a few possible classes only) and had to rely on a "very useful and flexible" method called #ifTrue:ifFalse:ifNil:ifEmpty:otherwise: .Obviously, you can only imagine the rest of the "logic" involved where this method was called... Double dispatching would have been so simpler and more elegant. It felt like doing BASIC a class browser !
I'm not against change when needed. I'm not against suggestions. I'm not against speed improvements. But I'm not for speed at all costs, especially code readability. If we want speed, it's in the VM we have to implement it. Cincom rarely relied on ugly Smalltalk code implementations to make VW faster. They pushed the VM. Not the Collection hierrachy, not the Number hierarchy, not the Stream, etc.
Besides, performance arguments is a slippery slope. What about memory consumption? Which road should we take ? It's fast but it instantiates 10 million objects or it's small and used 3Ks of memory but runs 5 seconds slower? There's always another side to what "efficiency" means to everyone.
My 2 cents!
:)
----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein)
------------------------------------------------------------------------ *From:* "Schwab,Wilhelm K" <bschwab@anest.ufl.edu> *To:* "Pharo-project@lists.gforge.inria.fr" <Pharo-project@lists.gforge.inria.fr> *Sent:* Sun, February 13, 2011 12:13:41 PM *Subject:* Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
Read the Federalist Papers and Bastiat's "The Law," and then we can talk about democracy, one illustration of which is three wolves and a sheep voting on the dinner menu. In its raw form, yes, I argue against democracy, aka mob rule.
However, we are not talking about taking someone's life, liberty or property here: this is software, and one can always retain #caseOf: in any image. However, a vote seems reasonable. I would be just as willing to accept the ruling of the benign dictators.
A switch often suggests inadequate reification (aka direct polymorphism or double dispatch might be in order), but I sometimes resort to a dictionary as a quick way to map numbers or strings to actions. Since landing in Pharo, I have been using the modified stream protocol I developed in response to default actions, which I consider to be a disaster in the making. Others are less worried about it. It is fairly easy to have some code that one loads into an image. I do it for streams, others can do it for case statements.
The above said, one thing I don't like is "you can't do that because I think its' ugly." Perhaps a compromise for Stef to consider is to clean the uses of the method so it is not used in the image (effectively removing it), but leave it in place for those who want to use it their own code??
Bill
________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr <mailto:pharo-project-bounces@lists.gforge.inria.fr> [pharo-project-bounces@lists.gforge.inria.fr <mailto:pharo-project-bounces@lists.gforge.inria.fr>] On Behalf Of Benoit St-Jean [bstjean@yahoo.com <mailto:bstjean@yahoo.com>] Sent: Sunday, February 13, 2011 9:43 AM To: Pharo-project@lists.gforge.inria.fr <mailto:Pharo-project@lists.gforge.inria.fr> Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
Let's get to the point here... Most people will tell you it's an awful "beast" that doesn't belong to the OO and Smalltalk world. If I *love* case statements and I absolutely need them, I can code in C. If I *love* case statements and I absolutely need them, nothing prevents me from adding them to the image as my own-superoptimized extension. You'll always find something, someone, somewhere who could argue about the need for such a thing but in reality, I guess this method has always bugged most Smalltalkers... It's ugly, not OO, not good style and good practice, not essential and not needed by 99% of the people here (and if it's sooooooooooo needed, how do you explain that all other Smalltalk vendors haven't implement it as part of their core libraries ?).
So let's vote (you won't argue against democracy, won't you?!) for the removal of #caseOf:otherwise: and let's move forward onto more important business.
On a less serious note, let's all remember what Spock said:
"Were I to invoke logic, however, logic clearly dictates that the needs of the many outweigh the needs of the few"
Let's remove this thing!
+1
P.S. Performance-wise, if you always need "optimized" code, you can always rely on primitives & plugins... Let's not go performance-frenzy here! We don't want to end up in an environment where all the code is unreadable... Clarity & simplicity are good, not evil in Smalltalk!
----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein)
________________________________ From: Levente Uzonyi <leves@elte.hu <mailto:leves@elte.hu>> To: Pharo-project@lists.gforge.inria.fr <mailto:Pharo-project@lists.gforge.inria.fr> Sent: Sun, February 13, 2011 8:50:53 AM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
On Sun, 13 Feb 2011, Sven Van Caekenberghe wrote:
On 12 Feb 2011, at 18:41, Levente Uzonyi wrote:
~27x slowdown in this case.
I personally never heard of #caseOf:otherwise !
It feels like a hack that is not often needed.
You don't need it often, but it's sometimes useful.
If after writing correct code you need to optimize integer/byte
handling, there are many solutions, check any book on algorithms, most of them are using table dispatch.
The blocks of #caseOf: are not just boilerplate code, you can evaluate any expression there. It's cumbersome to do that with table based dispatch.
Another problem in your benchmark is that you keep the creation of the
dynamic array inside the code to measure, while in the compiler primitive case it is of course compiled away, that alone makes a huge difference:
It's not a problem, it's intentional. See the mail that I replied to.
Levente
(timings on my machine)
[ 1 to: 10 do: [ :each | each caseOf: { [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } otherwise: [ $x ] ] ] bench. '8,920,000 per second.'
[ 1 to: 10 do: [ :each | ({ [ 1 ] -> [ $a ]. [ 2 ] -> [ $b ]. [ 3 ] -> [ $c ]. [ 4 ] -> [ $d ]. [ 5 ] -> [ $e ] } detect: [ :ea | ea key value = each ] ifNone: [ [ $x ] ]) value ] ] bench. '70,600 per second.'
| actions | actions := { [ $a ]. [ $b ]. [ $c ]. [ $d ]. [ $e ]. [ $x ]. [ $x ]. [
$x ]. [ $x ]. [ $x ]. }.
[ 1 to: 10 do: [ :each | (actions at: each) value ] ] bench. '3,230,000 per second.'
| letters | letters := 'abcdexxxxx'. [ 1 to: 10 do: [ :each | letters at: each ] ] bench. '8,930,000 per second.'
If other Smalltalks can live without it, so can we.
Sven
-- Janko Mivšek AIDA/Web Smalltalk Web Application Server http://www.aidaweb.si
On Fri, Feb 11, 2011 at 1:43 PM, stephane ducasse <stephane.ducasse@free.fr>wrote:
Hi guys
let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all.
| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z
=> "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] "
there is one user which I fixing right now.
please don't. It is used in many places in Cog and would be extremely uncomfortable to live without.
Stef
On 14 February 2011 22:38, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Fri, Feb 11, 2011 at 1:43 PM, stephane ducasse <stephane.ducasse@free.fr> wrote:
Hi guys
let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all.
| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z
=> "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] "
there is one user which I fixing right now.
please don't. Â It is used in many places in Cog and would be extremely uncomfortable to live without.
Yes, i mentioned that too.. It is strange however that the only 'senders' of these messages in VMMaker is: TMethod>>prepareMethodIn: aCodeGen ... (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue: [replacements at: node put: (self buildSwitchStmt: node)]]]. ahh... probably it means that system navigation can't detect them , because they are 'inlined' and there is no references to these selectors from methods where it used. But if you look at code there, VMMaker won't stop working if we remove compiler support of these guys, because it just reacts on a message-send level by checking if it a special selector, so it will be translated to switch statement in C. Oh.. or perhaps because code using #dispatchOn:in: :)
Stef
-- Best regards, Igor Stasenko AKA sig.
On Mon, Feb 14, 2011 at 1:58 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 14 February 2011 22:38, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Fri, Feb 11, 2011 at 1:43 PM, stephane ducasse <
stephane.ducasse@free.fr>
wrote:
Hi guys
let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all.
| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf:
z
=> "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] "
there is one user which I fixing right now.
please don't. It is used in many places in Cog and would be extremely uncomfortable to live without.
Yes, i mentioned that too..
It is strange however that the only 'senders' of these messages in VMMaker is:
TMethod>>prepareMethodIn: aCodeGen ... (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue: [replacements at: node put: (self buildSwitchStmt: node)]]].
ahh... probably it means that system navigation can't detect them , because they are 'inlined' and there is no references to these selectors from methods where it used.
That's right. The compiler inlines caseOf: into a series of comparisons and jumps. One way to find some uses (those without an explicit otherwise clause) is to look for senders of #caseError.
But if you look at code there, VMMaker won't stop working if we remove compiler support of these guys, because it just reacts on a message-send level by checking if it a special selector, so it will be translated to switch statement in C.
But we /will/ lose the ability to load code including it. This clearly isn't any kind of solution.
Oh.. or perhaps because code using #dispatchOn:in: :)
cheers Eliot
Stef
-- Best regards, Igor Stasenko AKA sig.
Eliot you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined - it could be packaged with VMMaker Are these two points correct? Stef
On Tue, Feb 15, 2011 at 08:00:18AM +0100, St?phane Ducasse wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined - it could be packaged with VMMaker
Are these two points correct?
No. VMMaker is used in many images, not just Pharo. And #caseOf: is used in packages other than VMMaker. So moving it into the VMMaker package would be a Bad Thing To Do. Dave
On 15 February 2011 12:50, David T. Lewis <lewis@mail.msen.com> wrote:
On Tue, Feb 15, 2011 at 08:00:18AM +0100, St?phane Ducasse wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that    - it does not need to be inlined    - it could be packaged with VMMaker
Are these two points correct?
No.
VMMaker is used in many images, not just Pharo. And #caseOf: is used in packages other than VMMaker. So moving it into the VMMaker package would be a Bad Thing To Do.
I agree. Then probably, Pharo should move it to separate 'Crap-compat' package. ;-P You don't need to remove #caseOf: implementation. I can stay. Just remove a compiler hacks for it :) P.S. i patched MessageNode class>>initialize to test if VMMaker can work without compiler support of caseof: and as it was expected it works quite well. I recompiled VMMaker package and then generated full source code of everything, and then built VM. No any errors.
Dave
-- Best regards, Igor Stasenko AKA sig.
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined - it could be packaged with VMMaker
Are these two points correct?
No.
? Apparently igor is just saying the contrary. You probably say no for the second point. I can understand that when we want to generate switch in C this is better to have that at the AST level. Now I do not see why this would be needed to inline it.
VMMaker is used in many images, not just Pharo. And #caseOf: is used in packages other than VMMaker.
Do you have a list?
So moving it into the VMMaker package would be a Bad Thing To Do.
I agree.
Then probably, Pharo should move it to separate 'Crap-compat' package.
Yes this is what I will do. I will keep that name and put a big warning.
;-P
You don't need to remove #caseOf: implementation. I can stay.
Well yes we can always turn around. Now in my house I regularly empty my garbage can.
Just remove a compiler hacks for it :)
P.S. i patched MessageNode class>>initialize to test if VMMaker can work without compiler support of caseof: and as it was expected it works quite well.
I recompiled VMMaker package and then generated full source code of everything, and then built VM. No any errors.
Good to know that. We should rewrite all the users of caseOf: in Pharo and add a lint rule checking them and one day we will remove it. Because we cannot drag all these stuffs forever. Stef
2011/2/15 Igor Stasenko <siguctua@gmail.com>:
On 15 February 2011 12:50, David T. Lewis <lewis@mail.msen.com> wrote:
On Tue, Feb 15, 2011 at 08:00:18AM +0100, St?phane Ducasse wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that    - it does not need to be inlined    - it could be packaged with VMMaker
Are these two points correct?
No.
VMMaker is used in many images, not just Pharo. And #caseOf: is used in packages other than VMMaker. So moving it into the VMMaker package would be a Bad Thing To Do.
I agree. Then probably, Pharo should move it to separate 'Crap-compat' package.
;-P
Agree, that's the way to go, and you handle it with a Pharo specific ConfigurationOf... Nicolas
You don't need to remove #caseOf: implementation. I can stay. Just remove a compiler hacks for it :)
P.S. i patched MessageNode class>>initialize to test if VMMaker can work without compiler support of caseof: and as it was expected it works quite well.
I recompiled VMMaker package and then generated full source code of everything, and then built VM. No any errors.
Dave
-- Best regards, Igor Stasenko AKA sig.
Em 15/02/2011 10:37, Igor Stasenko < siguctua@gmail.com > escreveu: Whereas I understand we are community of spirited and humorous programmers, I think that statements like:
I agree. Then probably, Pharo should move it to separate 'Crap-compat' package.
Are not amenable to the "good energy" Stef is willing to have in the Pharo team.
;-P
And the emoticon puts a tongue! The 'nickname' brings a judgment of value which I think may stir more feelings and doesn't bring anything useful to Pharo...
You don't need to remove #caseOf: implementation. I can stay. Just remove a compiler hacks for it :) P.S. i patched MessageNode class>>initialize to test if VMMaker can work without compiler support of caseof: and as it was expected it works quite well. I recompiled VMMaker package and then generated full source code of everything, and then built VM. No any errors.
And what would be the results of Levente's benchmark? -- Best regards, Igor Stasenko AKA sig.
On 15 February 2011 20:15, <csrabak@bol.com.br> wrote:
Em 15/02/2011 10:37, Igor Stasenko < siguctua@gmail.com > escreveu:
Whereas I understand we are community of spirited and humorous programmers, I think that statements like:
I  agree.   Then  probably,  Pharo  should  move  it  to  separate 'Crap-compat' package.
Are not amenable to the "good energy" Stef is willing to have in the Pharo team.
 ;-P
And the emoticon puts a tongue!
The 'nickname' brings a judgment of value which I think may stir more feelings and doesn't bring anything useful to Pharo...
Yes, in this discussion i wearing hat of an asshole. With humor , of course. Hey.. i'm not killing people and don't burning heretics. Also, the importance of outcome of this discussion is too small for being taken too seriously. I can live with or without #caseOf: (but better without), so relax and have fun :)
 You don't need to remove  #caseOf: implementation. I can stay. Just remove a compiler hacks for it :)  P.S. i patched MessageNode class>>initialize to test if VMMaker can work without compiler  support of caseof: and as  it was expected it works quite well.  I recompiled VMMaker package and then generated full source code of everything, and then built VM. No any errors.
And what would be the results of Levente's benchmark?
I don't care. Read about hammer and microscope.
-- Best regards, Igor Stasenko AKA sig.
-- Best regards, Igor Stasenko AKA sig.
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
Are these two points correct?
No, IMO, definitely not.
Stef
On 15 February 2011 19:59, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that     - it does not need to be inlined
No. Â If it is not inlined the simulator will go *much* slower. Â e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 Â ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it: ^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF ? Or this will be slower than caseOf: ?
    - it could be packaged with VMMaker
No. Â It needs to be in the compiler to be inlined. Â Why have you got on this hobby-horse? Â It is a non-issue. Â caseOf: ios not widelty used but extremely useful in certain circumstances. Â This has the feeling of a religious pogrom, not a rational approach to the system. Â IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me.
From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On Tue, Feb 15, 2011 at 11:18 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 15 February 2011 19:59, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the method. Further, it is only one example. I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On 15 February 2011 20:58, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Tue, Feb 15, 2011 at 11:18 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 15 February 2011 19:59, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that     - it does not need to be inlined
No. Â If it is not inlined the simulator will go *much* slower. Â e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 Â ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. Â I just copied the method. Â Further, it is only one example. Â I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. Â It is making unnecessary work. Â Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Â Can't we try and be constructive?
i'm not forcing you or someone else to take it out. I just don't see a need to keep it in compiler, because its not worth it. It adds too much complexity to code generation and decompilation. Maybe it will be a lot slower without compiler support. But i'd rather implement a primitive which will speed up a dictionary lookup by a factor of X, than keep supporting this huge pile of complexity in compiler.
    - it could be packaged with VMMaker
No. Â It needs to be in the compiler to be inlined. Â Why have you got on this hobby-horse? Â It is a non-issue. Â caseOf: ios not widelty used but extremely useful in certain circumstances. Â This has the feeling of a religious pogrom, not a rational approach to the system. Â IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
-- Best regards, Igor Stasenko AKA sig.
Eliot I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle. BTW why marcus and jorge work on Opal because the compiler is just working good? Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar. Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done. Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the method. Further, it is only one example. I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Case statements are not in themselves evil in the right context. The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken. As my first wife said "don't sweat the petty stuff; pet the sweaty stuff". BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. It can be used with anything. Expressions, class constants etc. BTW why marcus and jorge work on Opal because the compiler is just working
good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C): CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR] -> [self computeShiftRRSize]. [LogicalShiftRightRR] -> [self computeShiftRRSize]. [ArithmeticShiftRightRR] -> [self computeShiftRRSize]. [AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] -> [^maxSize := 4]. "Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the method. Further, it is only one example. I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
2011/2/15 Eliot Miranda <eliot.miranda@gmail.com>:
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. Â There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Â Case statements are not in themselves evil in the right context. Â The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken. As my first wife said "don't sweat the petty stuff; pet the sweaty stuff".
BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. Â It can be used with anything. Â Expressions, class constants etc.
BTW why marcus and jorge work on Opal because the compiler is just working good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C): CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. Â This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. Â The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR] -> [self computeShiftRRSize]. [LogicalShiftRightRR] -> [self computeShiftRRSize]. [ArithmeticShiftRightRR] -> [self computeShiftRRSize]. [AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] -> [^maxSize := 4]. "Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
In which case the alternative could be to reify Instructions and let them respondsTo: maxSize, but one would still need a decoder integer -> InstructionClass. But if it is for the benefit of a single method, it's legitimate to wonder why bother and create so many classes. Nicolas
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that     - it does not need to be inlined
No. Â If it is not inlined the simulator will go *much* slower. Â e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 Â ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. Â I just copied the method. Â Further, it is only one example. Â I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. Â It is making unnecessary work. Â Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Â Can't we try and be constructive?
    - it could be packaged with VMMaker
No. Â It needs to be in the compiler to be inlined. Â Why have you got on this hobby-horse? Â It is a non-issue. Â caseOf: ios not widelty used but extremely useful in certain circumstances. Â This has the feeling of a religious pogrom, not a rational approach to the system. Â IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On Tue, Feb 15, 2011 at 1:10 PM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
2011/2/15 Eliot Miranda <eliot.miranda@gmail.com>:
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
I can understand that well. Now we could just let this code in VMMaker
and
not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Case statements are not in themselves evil in the right context. The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken. As my first wife said "don't sweat the petty stuff; pet the sweaty stuff".
BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. It can be used with anything. Expressions, class constants etc.
BTW why marcus and jorge work on Opal because the compiler is just
working
good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C): CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR] -> [self computeShiftRRSize]. [LogicalShiftRightRR] -> [self computeShiftRRSize]. [ArithmeticShiftRightRR] -> [self computeShiftRRSize]. [AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] -> [^maxSize := 4]. "Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
In which case the alternative could be to reify Instructions and let them respondsTo: maxSize, but one would still need a decoder integer -> InstructionClass.
That doesn't work in this context because the above has to be translated to c *without* classes.
But if it is for the benefit of a single method, it's legitimate to wonder why bother and create so many classes.
Nicolas
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the method. Further, it is only one example. I'm not going to rewrite
the
VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
2011/2/15 Eliot Miranda <eliot.miranda@gmail.com>:
On Tue, Feb 15, 2011 at 1:10 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2011/2/15 Eliot Miranda <eliot.miranda@gmail.com>:
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. Â There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Â Case statements are not in themselves evil in the right context. Â The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken. As my first wife said "don't sweat the petty stuff; pet the sweaty stuff".
BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. Â It can be used with anything. Â Expressions, class constants etc.
BTW why marcus and jorge work on Opal because the compiler is just working good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C): CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. Â This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. Â The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR] -> [self computeShiftRRSize]. [LogicalShiftRightRR] -> [self computeShiftRRSize]. [ArithmeticShiftRightRR] -> [self computeShiftRRSize]. [AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] -> [^maxSize := 4]. "Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
In which case the alternative could be to reify Instructions and let them respondsTo: maxSize, but one would still need a decoder integer -> InstructionClass.
That doesn't work in this context because the above has to be translated to c *without* classes.
doh, I engaged a process of generating a vm which generates a vm which generates a ... Should better read twice before posting an answer :) Nicolas
Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious. Stef (if you think that I focus on details then I'm certainly an idiot).
On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious.
OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
Stef (if you think that I focus on details then I'm certainly an idiot).
On 16 February 2011 18:15, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious.
OPAL is a Smalltalk compiler. Â I can therefore assume that it will compile Smalltalk. Â caseOf: is valid Smalltalk and so will be compiled by OPAL. Â Whether Marcus chooses to optimise caseOf: or not is up to him.
And this was the question from the beginning of this thread :) Except that not all realized that Stef were talking about new compiler (Opal), not existing one. I am perfectly fine with current state of Compiler.. and it is really not worth adding/removing something from it, because in Pharo plans to integrate new compiler infrastructure. So, it is obvious that any work on old compiler is a waste of time and energy.
Stef (if you think that I focus on details then I'm certainly an idiot).
-- Best regards, Igor Stasenko AKA sig.
Igor my point is how can we migrate from the old compiler to the new one that will probably not support inlining of caseOf: if we rely or have caseOf: in the old compiler. If we do not need case of inlining then we can remove it and we can also clean Object. Stef On Feb 16, 2011, at 6:42 PM, Igor Stasenko wrote:
On 16 February 2011 18:15, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious.
OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
And this was the question from the beginning of this thread :) Except that not all realized that Stef were talking about new compiler (Opal), not existing one. I am perfectly fine with current state of Compiler.. and it is really not worth adding/removing something from it, because in Pharo plans to integrate new compiler infrastructure. So, it is obvious that any work on old compiler is a waste of time and energy.
Stef (if you think that I focus on details then I'm certainly an idiot).
-- Best regards, Igor Stasenko AKA sig.
On Feb 16, 2011, at 6:15 PM, Eliot Miranda wrote:
On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote: Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious.
OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
This is exactly my point.
Stef (if you think that I focus on details then I'm certainly an idiot).
On Wed, Feb 16, 2011 at 12:04 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
On Feb 16, 2011, at 6:15 PM, Eliot Miranda wrote:
On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <
stephane.ducasse@inria.fr> wrote:
Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious.
OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
This is exactly my point.
No it's not. Your point was to raise two straw-=man arguments: 1. that Marcus and Jorge would have to deal with the decompiler (not an issue; the decompiler already deals with optimized caseOf: and the new decompiler will deal with optimized caseOf: just as it'll deal with optimized ifTrue: ifNotNil: et al). 2. that supporting caseOf: in optimized form will delay Opal (not an issue; Opal will optimize certain constructs, this is just one more and won't add a lot of time). So your point appears to be to try and justify removing caseOf: on spurious grounds by spreading FUD. This is so unlike you I'm having a hard time really understanding what's going on. best regards, Eliot
Stef (if you think that I focus on details then I'm certainly an idiot).
On 16/02/2011 20:13, Eliot Miranda wrote:
On Wed, Feb 16, 2011 at 12:04 PM, Stéphane Ducasse <stephane.ducasse@inria.fr <mailto:stephane.ducasse@inria.fr>> wrote:
On Feb 16, 2011, at 6:15 PM, Eliot Miranda wrote:
> > > On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <stephane.ducasse@inria.fr <mailto:stephane.ducasse@inria.fr>> wrote: > Eliot a final question. > So how will you handle OPAL compiler change in Cog? > Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? > Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. > Just curious. > > OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
This is exactly my point.
No it's not. Your point was to raise two straw-=man arguments: 1. that Marcus and Jorge would have to deal with the decompiler (not an issue; the decompiler already deals with optimized caseOf: and the new decompiler will deal with optimized caseOf: just as it'll deal with optimized ifTrue: ifNotNil: et al). 2. that supporting caseOf: in optimized form will delay Opal (not an issue; Opal will optimize certain constructs, this is just one more and won't add a lot of time).
So your point appears to be to try and justify removing caseOf: on spurious grounds by spreading FUD.
This is so unlike you I'm having a hard time really understanding what's going on.
Correct me if I'm wrong but isn't Stephane essentially saying that Opal will just demote #caseOf: from inlined special form to normal method? (Possibly so it can be unloadable instead of being pinned in the system by the compiler support). It seems to me that this shouldn't affect caseOf: use in Cog since the inlining there is handled by the SLang translator. Or have I totally misunderstood? Of course, where caseOf: is kept afterwards another question :)
On Thu, Feb 17, 2011 at 1:59 AM, Douglas Brebner < squeaklists@fang.demon.co.uk> wrote:
On 16/02/2011 20:13, Eliot Miranda wrote:
On Wed, Feb 16, 2011 at 12:04 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
On Feb 16, 2011, at 6:15 PM, Eliot Miranda wrote:
On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <
stephane.ducasse@inria.fr> wrote:
Eliot a final question. So how will you handle OPAL compiler change in Cog? Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. Just curious.
OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
This is exactly my point.
No it's not. Your point was to raise two straw-=man arguments: 1. that Marcus and Jorge would have to deal with the decompiler (not an issue; the decompiler already deals with optimized caseOf: and the new decompiler will deal with optimized caseOf: just as it'll deal with optimized ifTrue: ifNotNil: et al). 2. that supporting caseOf: in optimized form will delay Opal (not an issue; Opal will optimize certain constructs, this is just one more and won't add a lot of time).
So your point appears to be to try and justify removing caseOf: on spurious grounds by spreading FUD.
This is so unlike you I'm having a hard time really understanding what's going on.
Correct me if I'm wrong but isn't Stephane essentially saying that Opal will just demote #caseOf: from inlined special form to normal method? (Possibly so it can be unloadable instead of being pinned in the system by the compiler support). It seems to me that this shouldn't affect caseOf: use in Cog since the inlining there is handled by the SLang translator.
It certainly won't affect the production Cog since indeed that goes through Slang to emerge as C. However it will affect developing in Cog, which is done by rnning the simulator, and as I've shown case statements are used in some performance-critical parts of the system (byte access).
Or have I totally misunderstood?
Of course, where caseOf: is kept afterwards another question :)
I don't see why one would want to get rid of this useful functionality. There is nothing inherrently wrong with a flexible case statement. Its certainly far more preferrable than a performance-equivalent set of nested ifTrue:ifFalse:'s. Further, the dictionary/perform or multiple classes approaches only make sense at a certain scale (that's especially true of the dictionary/perform alternative since maintaining the dictionary is painful). So for me it makes absolutely no sense for a Squeak-derived Smalltalk dialect to eliminate a construct that is really useful in certain circumstances. That kind of thinking eliminates things like contexts and that's a slippery slope to eliminating the essential flexibility of the system. 2¢ Eliot
On 17/02/2011 18:08, Eliot Miranda wrote:
On Thu, Feb 17, 2011 at 1:59 AM, Douglas Brebner <squeaklists@fang.demon.co.uk <mailto:squeaklists@fang.demon.co.uk>> wrote:
On 16/02/2011 20:13, Eliot Miranda wrote:
On Wed, Feb 16, 2011 at 12:04 PM, Stéphane Ducasse <stephane.ducasse@inria.fr <mailto:stephane.ducasse@inria.fr>> wrote:
On Feb 16, 2011, at 6:15 PM, Eliot Miranda wrote:
> > > On Tue, Feb 15, 2011 at 11:50 PM, Stéphane Ducasse <stephane.ducasse@inria.fr <mailto:stephane.ducasse@inria.fr>> wrote: > Eliot a final question. > So how will you handle OPAL compiler change in Cog? > Do you require that marcus and jorge have to deal with decompiler of caseOf: in addition to all the rest? > Is it a strong requirement? Because then this is clear that Opal will be delayed. But may be it is not that important after all. > Just curious. > > OPAL is a Smalltalk compiler. I can therefore assume that it will compile Smalltalk. caseOf: is valid Smalltalk and so will be compiled by OPAL. Whether Marcus chooses to optimise caseOf: or not is up to him.
This is exactly my point.
No it's not. Your point was to raise two straw-=man arguments: 1. that Marcus and Jorge would have to deal with the decompiler (not an issue; the decompiler already deals with optimized caseOf: and the new decompiler will deal with optimized caseOf: just as it'll deal with optimized ifTrue: ifNotNil: et al). 2. that supporting caseOf: in optimized form will delay Opal (not an issue; Opal will optimize certain constructs, this is just one more and won't add a lot of time).
So your point appears to be to try and justify removing caseOf: on spurious grounds by spreading FUD.
This is so unlike you I'm having a hard time really understanding what's going on.
Correct me if I'm wrong but isn't Stephane essentially saying that Opal will just demote #caseOf: from inlined special form to normal method? (Possibly so it can be unloadable instead of being pinned in the system by the compiler support). It seems to me that this shouldn't affect caseOf: use in Cog since the inlining there is handled by the SLang translator.
It certainly won't affect the production Cog since indeed that goes through Slang to emerge as C. However it will affect developing in Cog, which is done by rnning the simulator, and as I've shown case statements are used in some performance-critical parts of the system (byte access).
Wasn't there mention of Opal having optimisations as extensions so you can have an optimised caseOf: without having it hardwired into the compiler?
Or have I totally misunderstood?
Of course, where caseOf: is kept afterwards another question :)
I don't see why one would want to get rid of this useful functionality. There is nothing inherrently wrong with a flexible case statement. Its certainly far more preferrable than a performance-equivalent set of nested ifTrue:ifFalse:'s. Further, the dictionary/perform or multiple classes approaches only make sense at a certain scale (that's especially true of the dictionary/perform alternative since maintaining the dictionary is painful). So for me it makes absolutely no sense for a Squeak-derived Smalltalk dialect to eliminate a construct that is really useful in certain circumstances. That kind of thinking eliminates things like contexts and that's a slippery slope to eliminating the essential flexibility of the system.
I wasn't arguing for getting rid of it entirely, I prefer it to dictionary/perform which I dislike for some reason
Eliot, Now I fully understand the pain you'd have to go through (and others involved in the VM) if we'd remove this method we don't "like"... I guess it's way easier to live with #caseOf: than live without it... CogIA32Compiler>>#computeMaximumSize, when one method is worth a thousand words... ----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein) ________________________________ From: Eliot Miranda <eliot.miranda@gmail.com> To: Pharo-project@lists.gforge.inria.fr Sent: Tue, February 15, 2011 3:56:11 PM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise: On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote: Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Case statements are not in themselves evil in the right context. The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken. As my first wife said "don't sweat the petty stuff; pet the sweaty stuff". BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. It can be used with anything. Expressions, class constants etc. BTW why marcus and jorge work on Opal because the compiler is just working good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C): CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label]-> [^maxSize := 0]. [AlignmentNops]-> [^maxSize := (operands at: 0) - 1]. [Fill16]-> [^maxSize := 2]. [Fill32]-> [^maxSize := 4]. [FillFromWord]-> [^maxSize := 4]. [Nop]-> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ]-> [^maxSize := 1]. [IDIVR]-> [^maxSize := 2]. [IMULRR]-> [^maxSize := 3]. [CPUID]-> [^maxSize := 2]. [CMPXCHGAwR]-> [^maxSize := 7]. [CMPXCHGMwrR]-> [^maxSize := 8]. [LFENCE]-> [^maxSize := 3]. [MFENCE]-> [^maxSize := 3]. [SFENCE]-> [^maxSize := 3]. [LOCK]-> [^maxSize := 1]. [XCHGAwR]-> [^maxSize := 6]. [XCHGMwrR]-> [^maxSize := 7]. [XCHGRR]-> [^maxSize := 2]. "Control" [Call]-> [^maxSize := 5]. [JumpR]-> [^maxSize := 2]. [Jump]-> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong]-> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered]-> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered]-> [self resolveJumpTarget. ^maxSize := 6]. [RetN]-> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR]-> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR]-> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR]-> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR]-> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR]-> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR]-> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR]-> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR]-> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR]-> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR]-> [^maxSize := 2]. [AndRR]-> [^maxSize := 2]. [CmpRR]-> [^maxSize := 2]. [OrRR]-> [^maxSize := 2]. [XorRR]-> [^maxSize := 2]. [SubRR]-> [^maxSize := 2]. [NegateR]-> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR]-> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR]-> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR]-> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR]-> [self computeShiftRRSize]. [LogicalShiftRightRR]-> [self computeShiftRRSize]. [ArithmeticShiftRightRR]-> [self computeShiftRRSize]. [AddRdRd]-> [^maxSize := 4]. [CmpRdRd]-> [^maxSize := 4]. [SubRdRd]-> [^maxSize := 4]. [MulRdRd]-> [^maxSize := 4]. [DivRdRd]-> [^maxSize := 4]. [SqrtRd]-> [^maxSize := 4]. "Data Movement" [MoveCqR]-> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR]-> [^maxSize := 5]. [MoveRR]-> [^maxSize := 2]. [MoveAwR]-> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw]-> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr]-> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r]-> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR]-> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr]-> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR]-> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd]-> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR]-> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR]-> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR]-> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR]-> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR]-> [^maxSize := 1]. [PushR]-> [^maxSize := 1]. [PushCw]-> [^maxSize := 5]. [PrefetchAw]-> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd]-> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the method. Further, it is only one example. I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On 15 February 2011 22:28, Benoit St-Jean <bstjean@yahoo.com> wrote:
Eliot,
Now I fully understand the pain you'd have to go through (and others involved in the VM) if we'd remove this method we don't "like"... I guess it's way easier to live with #caseOf: than live without it...
yeah, in smalltalk you can just reify it to a lot of classes (one for each instruction) and implement #computeMaximumSize per each. Oh.. and you even don't have to do that per each.. if you look at code, it has size=6 for jumps. So, you can implement only 1 method in base 'jump' class, while others will simply reuse it.
CogIA32Compiler>>#computeMaximumSize, when one method is worth a thousand words...
----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein)
________________________________ From: Eliot Miranda <eliot.miranda@gmail.com> To: Pharo-project@lists.gforge.inria.fr Sent: Tue, February 15, 2011 3:56:11 PM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. Â There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Â Case statements are not in themselves evil in the right context. Â The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken. As my first wife said "don't sweat the petty stuff; pet the sweaty stuff".
BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. Â It can be used with anything. Â Expressions, class constants etc.
BTW why marcus and jorge work on Opal because the compiler is just working good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C): CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. Â This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. Â The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR] -> [self computeShiftRRSize]. [LogicalShiftRightRR] -> [self computeShiftRRSize]. [ArithmeticShiftRightRR] -> [self computeShiftRRSize]. [AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] -> [^maxSize := 4]. "Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that     - it does not need to be inlined
No. Â If it is not inlined the simulator will go *much* slower. Â e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 Â ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. Â I just copied the method. Â Further, it is only one example. Â I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. Â It is making unnecessary work. Â Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Â Can't we try and be constructive?
    - it could be packaged with VMMaker
No. Â It needs to be in the compiler to be inlined. Â Why have you got on this hobby-horse? Â It is a non-issue. Â caseOf: ios not widelty used but extremely useful in certain circumstances. Â This has the feeling of a religious pogrom, not a rational approach to the system. Â IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
-- Best regards, Igor Stasenko AKA sig.
But it looks like a DSL to me. So caseOf: could be moved to Cog. Stef On Feb 15, 2011, at 10:28 PM, Benoit St-Jean wrote:
Eliot,
Now I fully understand the pain you'd have to go through (and others involved in the VM) if we'd remove this method we don't "like"... I guess it's way easier to live with #caseOf: than live without it...
CogIA32Compiler>>#computeMaximumSize, when one method is worth a thousand words...
----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein)
From: Eliot Miranda <eliot.miranda@gmail.com> To: Pharo-project@lists.gforge.inria.fr Sent: Tue, February 15, 2011 3:56:11 PM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote: Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Case statements are not in themselves evil in the right context. The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken.
As my first wife said "don't sweat the petty stuff; pet the sweaty stuff".
BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. It can be used with anything. Expressions, class constants etc.
BTW why marcus and jorge work on Opal because the compiler is just working good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C):
CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0 ifTrue: [1] ifFalse: [3]]. "Arithmetic" [AddCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AndCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [OrCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [SubCqR] -> [^maxSize := (self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [(self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]]. [AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1 ifTrue: [2] ifFalse: [3]]. [LogicalShiftLeftRR] -> [self computeShiftRRSize]. [LogicalShiftRightRR] -> [self computeShiftRRSize]. [ArithmeticShiftRightRR] -> [self computeShiftRRSize]. [AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] -> [^maxSize := 4]. "Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]]. [MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX ifTrue: [5] ifFalse: [6]]. [MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 2)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [4] ifFalse: [7]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [5] ifFalse: [8]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0)) ifTrue: [3] ifFalse: [6]) + ((self concreteRegister: (operands at: 1)) = ESP ifTrue: [1] ifFalse: [0])]. [MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [5] ifFalse: [4]]. [MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 1)) = EBP ifTrue: [4] ifFalse: [3]]. [MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP. ^maxSize := (self concreteRegister: (operands at: 2)) = EBP ifTrue: [4] ifFalse: [3]]. [PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]]. "Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the method. Further, it is only one example. I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On Tue, Feb 15, 2011 at 11:17 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
But it looks like a DSL to me.
No its not. caseOf: is valid Smalltalk. It is another control structure defined in the library rather than by the language, just like do:, inject:into: et al. It is extremely useful in certain circumstances. It can be (and is) optimized. Functional languages support case statements that are conceptually similar. caseOf: (and those of functional languages) are *much* more powerful than the switch statement of C: caseOf: can dispatch on arbitrary values, not just integer indices; caseOf:'s selectors (the things on the left of the ->'s) can be expressions, not just constants.
So caseOf: could be moved to Cog.
Fine. Let me be equally pig-headed then. I'm not going to spend any more energy on this, and I'm not going to spend any more energy on Cog in Pharo. This is ridiculous.
Stef
On Feb 15, 2011, at 10:28 PM, Benoit St-Jean wrote:
Eliot,
Now I fully understand the pain you'd have to go through (and others involved in the VM) if we'd remove this method we don't "like"... I guess it's way easier to live with #caseOf: than live without it...
CogIA32Compiler>>#computeMaximumSize, when one method is worth a thousand words...
----------------- Benoit St-Jean Yahoo! Messenger: bstjean A standpoint is an intellectual horizon of radius zero. (Albert Einstein)
From: Eliot Miranda <eliot.miranda@gmail.com> To: Pharo-project@lists.gforge.inria.fr Sent: Tue, February 15, 2011 3:56:11 PM Subject: Re: [Pharo-project] could we agree to remove caseOf: and caseOf:otherwise:
On Tue, Feb 15, 2011 at 12:39 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote: Eliot
I can understand that well. Now we could just let this code in VMMaker and not inlining. We fix 8 users and we are done. I have concerned that we have a complex solution because it is complex for a couple of use case. Of course we can do nothing (and we will probably not do it now) but in that case we can also stop pharo right now because a large part of the system could follow the exact same principle.
That's a false distinction. There's nothing wrong with caseOf: and not addressing it will not leave Pharo any the worse. Case statements are not in themselves evil in the right context. The main problems with the index/dictionary approach are that a) the solution is no longer contained in a single method b) the dictionary is metadata that needs to be updated in an initialize method; forget to initialize the dictionary when an index changes and your program is broken.
As my first wife said "don't sweat the petty stuff; pet the sweaty stuff".
BTW, there's a false assumption that has been stated in this thread that the caseOf: statement is only used with explicit integers. It can be used with anything. Expressions, class constants etc.
BTW why marcus and jorge work on Opal because the compiler is just working good?
Now I will focus on 1.2, FS, Opal if I can help, and the rest but caseOf: will be in our radar.
Just a remark if people would have spend the time to write mail to fix the users of caseof: in the image and other non VMmaker package we would have get already done.
Fix this (rhetorical - I think this is /much/ better as a single case statement than as an index/dictionary refactoring, both in Smalltalk and when translated to C):
CogIA32Compiler>>computeMaximumSize "Compute the maximum size for each opcode. This allows jump offsets to be determined, provided that all backward branches are long branches." "N.B. The ^maxSize := N forms are to get around the compiler's long branch limits which are exceeded when each case jumps around the otherwise." opcode caseOf: { "Noops & Pseudo Ops" [Label] -> [^maxSize := 0]. [AlignmentNops] -> [^maxSize := (operands at: 0) - 1]. [Fill16] -> [^maxSize := 2]. [Fill32] -> [^maxSize := 4]. [FillFromWord] -> [^maxSize := 4]. [Nop] -> [^maxSize := 1]. "Specific Control/Data Movement" [CDQ] -> [^maxSize := 1]. [IDIVR] -> [^maxSize := 2]. [IMULRR] -> [^maxSize := 3]. [CPUID] -> [^maxSize := 2]. [CMPXCHGAwR] -> [^maxSize := 7]. [CMPXCHGMwrR] -> [^maxSize := 8]. [LFENCE] -> [^maxSize := 3]. [MFENCE] -> [^maxSize := 3]. [SFENCE] -> [^maxSize := 3]. [LOCK] -> [^maxSize := 1]. [XCHGAwR] -> [^maxSize := 6]. [XCHGMwrR] -> [^maxSize := 7]. [XCHGRR] -> [^maxSize := 2]. "Control" [Call] -> [^maxSize := 5]. [JumpR] -> [^maxSize := 2]. [Jump] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpLong] -> [self resolveJumpTarget. ^maxSize := 5]. [JumpZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6]. [JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6]. [RetN] -> [^maxSize := (operands at: 0) = 0
ifTrue: [1]
ifFalse: [3]].
"Arithmetic" [AddCqR] -> [^maxSize := (self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[AndCqR] -> [^maxSize := (self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[CmpCqR] -> [^maxSize := (self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[OrCqR] -> [^maxSize := (self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[SubCqR] -> [^maxSize := (self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[AddCwR] -> [^maxSize := (self
concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[CmpCwR] -> [^maxSize := (self
concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[SubCwR] -> [^maxSize := (self
concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[XorCwR] -> [^maxSize := (self
concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[AddRR] -> [^maxSize := 2]. [AndRR] -> [^maxSize := 2]. [CmpRR] -> [^maxSize := 2]. [OrRR] -> [^maxSize := 2]. [XorRR] -> [^maxSize := 2]. [SubRR] -> [^maxSize := 2]. [NegateR] -> [^maxSize := 2]. [LoadEffectiveAddressMwrR] -> [^maxSize := ((self
isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[LogicalShiftLeftCqR] -> [^maxSize := (operands
at: 0) = 1
ifTrue: [2]
ifFalse: [3]].
[LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) =
1
ifTrue: [2]
ifFalse: [3]].
[ArithmeticShiftRightCqR] -> [^maxSize := (operands
at: 0) = 1
ifTrue: [2]
ifFalse: [3]].
[LogicalShiftLeftRR] -> [self
computeShiftRRSize].
[LogicalShiftRightRR] -> [self
computeShiftRRSize].
[ArithmeticShiftRightRR] -> [self
computeShiftRRSize].
[AddRdRd] -> [^maxSize := 4]. [CmpRdRd] -> [^maxSize := 4]. [SubRdRd] -> [^maxSize := 4]. [MulRdRd] -> [^maxSize := 4]. [DivRdRd] -> [^maxSize := 4]. [SqrtRd] ->
[^maxSize := 4].
"Data Movement" [MoveCqR] -> [^maxSize := (operands at: 0) =
0 ifTrue: [2] ifFalse: [5]].
[MoveCwR] -> [^maxSize := 5]. [MoveRR] -> [^maxSize := 2]. [MoveAwR] -> [^maxSize := (self
concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[MoveRAw] -> [^maxSize := (self
concreteRegister: (operands at: 0)) = EAX
ifTrue: [5]
ifFalse: [6]].
[MoveRMwr] -> [^maxSize := ((self isQuick:
(operands at: 1))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 2)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveRdM64r] -> [^maxSize := ((self isQuick: (operands
at: 1))
ifTrue: [5]
ifFalse: [8])
+ ((self concreteRegister: (operands at: 2)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveMbrR] -> [^maxSize := ((self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveRMbr] -> [^maxSize := ((self isQuick:
(operands at: 1))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 2)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveM16rR] -> [^maxSize := ((self isQuick: (operands
at: 0))
ifTrue: [4]
ifFalse: [7])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveM64rRd] -> [^maxSize := ((self isQuick: (operands
at: 0))
ifTrue: [5]
ifFalse: [8])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveMwrR] -> [^maxSize := ((self isQuick:
(operands at: 0))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveXbrRR] -> [self assert: (self concreteRegister:
(operands at: 0)) ~= ESP.
^maxSize := (self
concreteRegister: (operands at: 1)) = EBP
ifTrue: [5]
ifFalse: [4]].
[MoveXwrRR] -> [self assert: (self concreteRegister:
(operands at: 0)) ~= ESP.
^maxSize := (self
concreteRegister: (operands at: 1)) = EBP
ifTrue: [4]
ifFalse: [3]].
[MoveRXwrR] -> [self assert: (self concreteRegister:
(operands at: 1)) ~= ESP.
^maxSize := (self
concreteRegister: (operands at: 2)) = EBP
ifTrue: [4]
ifFalse: [3]].
[PopR] -> [^maxSize := 1]. [PushR] -> [^maxSize := 1]. [PushCw] -> [^maxSize := 5]. [PrefetchAw] -> [^maxSize := self hasSSEInstructions
ifTrue: [7] ifFalse: [0]].
"Conversion" [ConvertRRd] -> [^maxSize := 4] }. ^0 "to keep C compiler quiet"
Stef
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. I just copied the
method. Further, it is only one example. I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. It is making unnecessary work. Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Can't we try and be constructive?
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got
on this
hobby-horse? It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system. IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On Feb 16, 2011, at 6:12 PM, Eliot Miranda wrote:
On Tue, Feb 15, 2011 at 11:17 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote: But it looks like a DSL to me.
No its not. caseOf: is valid Smalltalk. It is another control structure defined in the library rather than by the language, just like do:, inject:into: et al. It is extremely useful in certain circumstances. It can be (and is) optimized. Functional languages support case statements that are conceptually similar. caseOf: (and those of functional languages) are *much* more powerful than the switch statement of C: caseOf: can dispatch on arbitrary values, not just integer indices; caseOf:'s selectors (the things on the left of the ->'s) can be expressions, not just constants.
So caseOf: could be moved to Cog.
Fine. Let me be equally pig-headed then. I'm not going to spend any more energy on this, and I'm not going to spend any more energy on Cog in Pharo. This is ridiculous.
Then perfect be mad at me and take all the pharoers in prison. This is the only solution. Since you have the power to do it and I cannot do anything about it. I let you choose if I'm a real assshole, a plain idiot or just that I suggest something to ease our future. what I suggest is to - stop inlining caeOf so that the transition path to OPAL is easier - let caseOf use for VMMaker. It would take 15 min to do that and probably 30 min to fix tools that are using caseOf: out of VMMaker. Stef
2011/2/15 Eliot Miranda <eliot.miranda@gmail.com>:
On Tue, Feb 15, 2011 at 11:18 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 15 February 2011 19:59, Eliot Miranda <eliot.miranda@gmail.com> wrote:
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that     - it does not need to be inlined
No. Â If it is not inlined the simulator will go *much* slower. Â e.g. CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 Â ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
so why not put it:
^ (long bitShift: (-8*lowBits) ) bitAnd: 16rFF
? Or this will be slower than caseOf: ?
Because that was the way the code was written. Â I just copied the method. Â Further, it is only one example. Â I'm not going to rewrite the VMMaker's uses of caseOf: jyst to suit some whim of purity. Â It is making unnecessary work. Â Taking it out is *much* more work (/and/ emotional energy) than just leaving it alone. Â Can't we try and be constructive?
I agree with Eliot, byteAt: byteAt:put: are the easy part to rewrite - plus they are copy/pasted a number of times ;) The other cog's caseOf: are tougher and if caseOf: just works, why bother... Nicolas
    - it could be packaged with VMMaker
No. Â It needs to be in the compiler to be inlined. Â Why have you got on this hobby-horse? Â It is a non-issue. Â caseOf: ios not widelty used but extremely useful in certain circumstances. Â This has the feeling of a religious pogrom, not a rational approach to the system. Â IIABDFI = If It Ain't Broke, Don't Fix It.
This concept kinda appeal to me. From other side, i am also strongly feel that house should be kept clean :)
Are these two points correct?
No, IMO, definitely not.
Stef
-- Best regards, Igor Stasenko AKA sig.
On Feb 15, 2011, at 7:59 PM, Eliot Miranda wrote:
On Mon, Feb 14, 2011 at 11:00 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote: Eliot
you use caseOf: for the generation of C in Slang and VM maker. Now this means that - it does not need to be inlined
No. If it is not inlined the simulator will go *much* slower. e.g.
CogVMSimulatorLSB>>byteAt: byteAddress | lowBits long | lowBits := byteAddress bitAnd: 3. long := self longAt: byteAddress - lowBits. ^(lowBits caseOf: { [0] -> [ long ]. [1] -> [ long bitShift: -8 ]. [2] -> [ long bitShift: -16 ]. [3] -> [ long bitShift: -24 ] }) bitAnd: 16rFF
Does simulator needs to be fast? Then I have no problem that this code is in VMMaker. If this is essential.
- it could be packaged with VMMaker
No. It needs to be in the compiler to be inlined. Why have you got on this hobby-horse?
Absolutely not. There are a lot of stuff that can follow the same argument. And at the end we will have a system with a lot of stuff nearly used and more or less useful. I want Object to be cleaned. I want a clean compiler. I want to minimize our pain. and not having to decompile caseOf: = less pain less works less maintenance.... I want to have a real clean kernel
It is a non-issue. caseOf: ios not widelty used but extremely useful in certain circumstances. This has the feeling of a religious pogrom, not a rational approach to the system.
This is what you believe but this is rationale. Why do we have 400 methods in Object, 800 in Morph (and we already removed a lot of them).
IIABDFI = If It Ain't Broke, Don't Fix It.
No sorry are telling to marcus that instead of doing something cool he should burn his time on decompiler for a message that is used by 3 tools? Am'i hearing you saying that? Please let me know instead of telling me that I focus on the wrong stuff to fix. And breaking senders and implementors and probably pretty printing. Do we care about having a decent compiler? This is more than 2 years that I want a compiler with an open infrastructure so that we can have first class instance variables (like in CLOS since 1990). I want to have Maggrite like meta description integrated and I want daemons in less than 10 lines of code. Not copying a complete compiler like in Tweak. We prototyped first class instance variable with **no** runtime cost in one afternoon 2 years ago and this is still not our image. Why because there are fucking stuff everywhere. When do we really invent something new in this wonderful community or are we just doomed to stay doing fucking maintenance of CRAPPPPPPY code. Because let us face it this is about that. I'm doing pharo to move on and reinvent the system. If we do not reconsider past choices why do we need filesystems? It works no so do not fix it. Streams too, Morphic yes it works, browser (come on we are the only system on earth where Car inherits from Wheel - yes us the inventors of OOP - laughable - you should see some of our students they laugh a lot. Because Browser inherits from StringHolder.... So do we want that because if we want that. I'm off.
Are these two points correct?
No, IMO, definitely not.
Stef
On Fri, Feb 11, 2011 at 1:43 PM, stephane ducasse <stephane.ducasse@free.fr> wrote: Hi guys
let us do another pass at cleaning and realigning the system. Could we agree to deprecate caseOf: and caseOf:otherwise:? it will simply the compiler, decompiler and also we do not need that at all.
| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z
=> "| z | z := {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. z detect: [:each | each key value = #b] "
there is one user which I fixing right now.
please don't. It is used in many places in Cog and would be extremely uncomfortable to live without.
Really? How can we help to remove this dependency? Can igor help? This means that the decompiler is more complex (more jump to analyze for a messages that is sent may be 10 times in total in the complete system). I will not compare with ifTrue:ifFalse: and the other inlined selectors that are really used. Stef
participants (21)
-
Adrien BARREAU -
Alain Plantec -
Benoit St-Jean -
Casimiro de Almeida Barreto -
csrabak@bol.com.br -
David T. Lewis -
Douglas Brebner -
Eliot Miranda -
Henrik Sperre Johansen -
Igor Stasenko -
Janko Mivšek -
Levente Uzonyi -
Miguel Cobá -
Nicolas Cellier -
Ricardo Moran -
Schwab,Wilhelm K -
stephane ducasse -
Stephen Taylor -
Stéphane Ducasse -
Sven Van Caekenberghe -
Tudor Girba