I'm missing something here... I tried implementing: MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value. But the notNilBlock is evaluated. I'm assuming it's being inlined. Is that right? How do I workaround? I also tried subclassing UndefinedObject, with the same result. Any ideas? ----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Actually looking at the bytecode, it is inlined. I performed this little experiment: MyClass>>foo MyNullClass new ifNil: [ Transcript show: 'Nil';cr ] ifNotNil: [ Transcript show: 'NotNil';cr ] So what it really does is MyNullClass new == nil ifTrue: [ Transcript show: 'Nil';cr ] ifFalse: [ Transcript show: 'NotNil';cr ]. (Well, the #ifTrue:ifFalse: is also inlined) So actually subclassing UndefinedObject doesn't work either, because of the #==. Also I think (I'm not completely sure about this), the #== doesn't perform a lookup and the VM takes care of that, so there is no way to change it's behavior by overriding it. About how to workaround... I have no idea =( Cheers, Alejandro 2014/1/22 Sean P. DeNigris <sean@clipperadams.com>
I'm missing something here... I tried implementing: MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value. But the notNilBlock is evaluated. I'm assuming it's being inlined. Is that right? How do I workaround?
I also tried subclassing UndefinedObject, with the same result.
Any ideas?
----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Not too sure which version of Pharo youâre using (image itâs 3) but Marcus recently mentioned a similar issue.
In Opal to remove the usage of #==, I removed it from the special selector array in the method: IRBytecodeGenerator class>>specialSelectorsArray ^ #(#+ 1 #- 1 #< 1 #> 1 #<= 1 #>= 1 #= 1 #~= 1 #* 1 #/ 1 #\\ 1 #@ 1 #bitShift: 1 #// 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #== 1 nil 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0)
Then I ran: IRBytecodeGenerator initialize. OpalCompiler recompileAll.
I looked in Pharo 3 image and tried the changes below: OCASTTranslator class>>initialize (removed line referring to the selector and then re-initialise) and then RBMessageNode>>isInlineIfNil (removed the reference to the selector so not picked up as inlined) Then try recompile: OpalCompiler recompileAll. Everything recompiles but then image dies so couldnât test it so I might be on wrong path ;) On 23 Jan 2014, at 5:51 AM, Alejandro Infante <alejandroinfante91@gmail.com> wrote: Actually looking at the bytecode, it is inlined. I performed this little experiment: MyClass>>foo MyNullClass new ifNil: [ Transcript show: 'Nil';cr ] ifNotNil: [ Transcript show: 'NotNil';cr ] So what it really does is MyNullClass new == nil ifTrue: [ Transcript show: 'Nil';cr ] ifFalse: [ Transcript show: 'NotNil';cr ]. (Well, the #ifTrue:ifFalse: is also inlined) So actually subclassing UndefinedObject doesn't work either, because of the #==. Also I think (I'm not completely sure about this), the #== doesn't perform a lookup and the VM takes care of that, so there is no way to change it's behavior by overriding it. About how to workaround... I have no idea =( Cheers, Alejandro 2014/1/22 Sean P. DeNigris <sean@clipperadams.com> I'm missing something here... I tried implementing: MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value. But the notNilBlock is evaluated. I'm assuming it's being inlined. Is that right? How do I workaround? I also tried subclassing UndefinedObject, with the same result. Any ideas? ----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
In that specialSelectorArray the number that follows a selector is the number of arguments it takes? So if we want to take out the #== we should remove the "1" at the right of the selector right? Also something really interesting (at least for me) is that "nil" is in that list, but I don't see "super" or "true". Also I thought that #new wasn't inlined, I'm (was) pretty sure I can override it. 2014/1/22 Carlo <snoobabk@gmail.com>
Not too sure which version of Pharo youâre using (image itâs 3) but Marcus recently mentioned a similar issue.
In Opal to remove the usage of #==, I removed it from the special selector array in the method: IRBytecodeGenerator class>>specialSelectorsArray ^ #(#+ 1 #- 1 #< 1 #> 1 #<= 1 #>= 1 #= 1 #~= 1 #* 1 #/ 1 #\\ 1 #@ 1 #bitShift: 1 #// 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #== 1 nil 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0)
Then I ran: IRBytecodeGenerator initialize. OpalCompiler recompileAll.
I looked in Pharo 3 image and tried the changes below: OCASTTranslator class>>initialize (removed line referring to the selector and then re-initialise) and then RBMessageNode>>isInlineIfNil (removed the reference to the selector so not picked up as inlined)
Then try recompile: OpalCompiler recompileAll. Everything recompiles but then image dies so couldnât test it so I might be on wrong path ;)
On 23 Jan 2014, at 5:51 AM, Alejandro Infante < alejandroinfante91@gmail.com> wrote:
Actually looking at the bytecode, it is inlined. I performed this little experiment:
MyClass>>foo MyNullClass new ifNil: [ Transcript show: 'Nil';cr ] ifNotNil: [ Transcript show: 'NotNil';cr ]
So what it really does is
MyNullClass new == nil ifTrue: [ Transcript show: 'Nil';cr ] ifFalse: [ Transcript show: 'NotNil';cr ].
(Well, the #ifTrue:ifFalse: is also inlined) So actually subclassing UndefinedObject doesn't work either, because of the #==. Also I think (I'm not completely sure about this), the #== doesn't perform a lookup and the VM takes care of that, so there is no way to change it's behavior by overriding it.
About how to workaround... I have no idea =(
Cheers, Alejandro
2014/1/22 Sean P. DeNigris <sean@clipperadams.com>
I'm missing something here... I tried implementing: MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value. But the notNilBlock is evaluated. I'm assuming it's being inlined. Is that right? How do I workaround?
I also tried subclassing UndefinedObject, with the same result.
Any ideas?
----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value.
Any ideas?
I've got a slightly different understanding of the null object pattern, perhaps. I would use it this way: MyClass is an abstract class that defines an interface that users would expect, with a subclass MyNullClass and MyConcreteClass. Where ever I send messages to the "MyClass", it could either be an instance of MyNullClass or MyConcreteClass. MyNullClass would implement the protocol of MyClass, but would behave differently. This is so that the users /senders of MyClass do not have to do if's to determine if it's talking to a null object or not. And this is where I wonder if I will try to implement the ifNil behviour on MyNullClass at all, because the senders have to know about the kind of thing it is talking to. But perhaps this is a different context. Otto
Hello, specific messages (control flow oriented messages) are inlined and you cannot override them (same problem in the old and the new compiler). In Opal we introduced some kind of settings to force the compiler not to inline messages when it is not needed. This can be done at method level with a pragma for example: MyClass>>#foo <compilerOptions: #(- optInlineIf)> ^ #myNonBooleanObject ifTrue: [ 1 ] ifFalse: [ 0 ] Or at class level, however at class level there are issue with monticello (therefore you would need to recompile your code after loading it). InstructionStream class>>#compiler ^ super compiler options: #(+ optLongIvarAccessBytecodes) See the list of options here: OpalCompiler class>>#defaultOptions You cannot in the current Pharo/Squeak disable the inlining of all the control flow messages or it crashes the image. It crashes for example due to the whileTrue: implementation (no stop condition without inlining) or the allObjectsDo: one (then you create a context per iteration). Usually, the compiler is not too aggressive when inlining loops (whileTrue:, to:do:, ...) so you should be able to override it in most cases, however it is very aggressive for condition (ifTrue:ifFalse:, ifNil:ifNotNil:, ...), so you cannot override those methods, except if you manually add compiler options as explained before. Making the compiler less aggressive for conditions drastically decrease Pharo overall performance. In addition, the compilers inline specific messages defined here: IRBytecodeGenerator class>>specialSelectorsArray. In Squeak they inline in addition of these messages the message #class. We decided not to do it in Pharo because it does not decrease performance nor increase the memory size by a noticeable value. There is no setting currently for these specific selectors. So you have to run the code specified by Carlo: In Opal to remove the usage of #==, I removed it from the special selector array in the method: IRBytecodeGenerator class>>specialSelectorsArray ^ #(#+ 1 #- 1 #< 1 #> 1 #<= 1 #>= 1 #= 1 #~= 1 #* 1 #/ 1 #\\ 1 #@ 1 #bitShift: 1 #// 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #== 1 nil 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0) Then I ran: IRBytecodeGenerator initialize. OpalCompiler recompileAll. That's all the ideas I had Sean :-) 2014/1/23 Otto Behrens <otto@finworks.biz>
MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value.
Any ideas?
I've got a slightly different understanding of the null object pattern, perhaps. I would use it this way:
MyClass is an abstract class that defines an interface that users would expect, with a subclass MyNullClass and MyConcreteClass.
Where ever I send messages to the "MyClass", it could either be an instance of MyNullClass or MyConcreteClass. MyNullClass would implement the protocol of MyClass, but would behave differently. This is so that the users /senders of MyClass do not have to do if's to determine if it's talking to a null object or not.
And this is where I wonder if I will try to implement the ifNil behviour on MyNullClass at all, because the senders have to know about the kind of thing it is talking to.
But perhaps this is a different context.
Otto
Thank you everyone. Yes, the subject is a bit misleading ;) I'll give you my exact use case to make things clearly⦠I'm cleaning up the globals ActiveWorld and World. There are methods such as Morph>>world that sometimes return one of the above, or nil. As part of the cleanup, I want a NullWorld that is indeed polymorphic with WorldMorph. However, I don't want to change too much at once because it's too easy to freeze the image. So I want to temporarily implement NullWorld>>#ifNil:ifNotNil: so that I can plug in the new object, without breaking all the existing code, so I can switch back to nil if I get in trouble. When it's working, I'll start to remove all the #ifNil:ifNotNil: sends as a 2nd phase. In light of this, what's the best way to proceed? ----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574p4738906.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
2014/1/24 Sean P. DeNigris <sean@clipperadams.com>
Thank you everyone. Yes, the subject is a bit misleading ;) I'll give you my exact use case to make things clearlyâ¦
I'm cleaning up the globals ActiveWorld and World. There are methods such as Morph>>world that sometimes return one of the above, or nil. As part of the cleanup, I want a NullWorld that is indeed polymorphic with WorldMorph. However, I don't want to change too much at once because it's too easy to freeze the image. So I want to temporarily implement NullWorld>>#ifNil:ifNotNil: so that I can plug in the new object, without breaking all the existing code, so I can switch back to nil if I get in trouble. When it's working, I'll start to remove all the #ifNil:ifNotNil: sends as a 2nd phase.
In light of this, what's the best way to proceed?
----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574p4738906.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Do you know this places where ifNil:ifNotNil: is called? If so, you coulde change them to ifWorldNil:ifWorldNotNil: and implement this on World, ActiveWorld, NullWorld and UndefinedObject.
On Jan 24, 2014, at 4:57 AM, "Nicolai Hess [via Smalltalk]" <ml-node+s1294792n4738969h27@n4.nabble.com> wrote:
Do you know this places where ifNil:ifNotNil: is called? If so, you coulde change them to ifWorldNil:ifWorldNotNil: and implement this on World, ActiveWorld, NullWorld and UndefinedObject. If I can't do it effectively with the compiler, that could be a good compromise. Thanks :)
----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574p4739061.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Tried in Pharo3.0 update: #30651 and the following worked: 1. OCASTTranslator class>>initialise Removed line referring to the selector and then re-initialise. 2. RBMessageNode>>isInlineIfNil Removed the reference to the ifNil:ifNotNil: selector so not picked up as inlined. 3. Created a class NullWorld and overrode the #ifNil:ifNotNil 4. Ran a quick test and it seemed to be working. Cheers Carlo On 24 Jan 2014, at 4:13 PM, Sean P. DeNigris <sean@clipperadams.com> wrote: On Jan 24, 2014, at 4:57 AM, "Nicolai Hess [via Smalltalk]" <[hidden email]> wrote:
Do you know this places where ifNil:ifNotNil: is called? If so, you coulde change them to ifWorldNil:ifWorldNotNil: and implement this on World, ActiveWorld, NullWorld and UndefinedObject. If I can't do it effectively with the compiler, that could be a good compromise. Thanks :) Cheers, Sean
View this message in context: Re: Null Object Pattern Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
On Jan 24, 2014, at 3:14 PM, Carlo-2 [via Smalltalk] <ml-node+s1294792n4739153h31@n4.nabble.com> wrote:
3. Created a class NullWorld and overrode the #ifNil:ifNotNil Thanks! I'll check that out :)
----- Cheers, Sean -- View this message in context: http://forum.world.st/Null-Object-Pattern-tp4738574p4739535.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
2014/1/23 Otto Behrens <otto@finworks.biz>:
MyNullClass>>#ifNil: nilBlock ifNotNil: notNilBlock nilBlock value.
Any ideas?
I've got a slightly different understanding of the null object pattern, perhaps.
Me too. A "null object" is an object that is polymorphic with some other. Eg. "Person" and "NullPerson". It is a good pattern to avoid testing for nil (#isNil, etc.) in domain objects, and also avoid MessageNotUnderstood exceptions during runtime (or NullPointerException). :) In one system we had NullNumber class (and singleton instance) to be polymorphic with Number for number attributes with three states (nil, 0, value). I don't know your particular use of MyNullClass, but looks like a NullUndefinedObject :) Regards! Esteban A. Maringolo
participants (7)
-
Alejandro Infante -
Carlo -
Clément Bera -
Esteban A. Maringolo -
Nicolai Hess -
Otto Behrens -
Sean P. DeNigris