Hi All,
Perhaps I am misunderstanding the behaviour of
I have a class SoupTag which holds a dictionary of attributes and a collection of children which are also soup tags.
As a shorthand for attribute access, SoupTag implements:
SoupTag>>doesNotUnderstand: aMessage (aMessage arguments size = 0) ifFalse: [^ super doesNotUnderstand: aMessage]. ^ attributes at: aMessage selector ifAbsent: [super doesNotUnderstand: aMessage]
So that a SoupTag with attribute id=100 would answer 100 to #id and DNU to any other selector. This seems to work fine but I'm having trouble implementing a flexible find: method. The test case is
tag := SoupTag new tag attributeAt: 'id' put: 'abc'. tag find: [:each | (each missing = 'xyz') or: [each id = 'abc']]
And so far I have simplemented this as:
SoupTag>>find: aBlock [(aBlock value: self) ifTrue: [^ self]] on: MessageNotUnderstood do: [:e | e resume: false]. children do: [:anElement | | found | found := anElement find: aBlock. found ifNotNil: [^ found]]. ^ nil
I expected this to effectively end up evaluating:
tag find: [:each | false or: [each id = 'abc']]
But all I get is infinite recursion from the doesNotUnderstand. I think this should work as this little test demonstrates:
[('abc' + 1) + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " prints 2 "
Any help is greatly appreciated.
Thanks, Zulq.
hello,
SoupTag>>doesNotUnderstand: aMessage (aMessage arguments size = 0) ifFalse: [^ super doesNotUnderstand: aMessage]. ^ attributes at: aMessage selector ifAbsent: [super doesNotUnderstand: aMessage]
this can be simpler, since the dictionary lookup will not confuse #id with #id:, so you can get rid of the arguments size test:
SoupTag>>doesNotUnderstand: aMessage ^ attributes at: aMessage selector ifAbsent: [super doesNotUnderstand: aMessage]
SoupTag>>find: aBlock [(aBlock value: self) ifTrue: [^ self]] on: MessageNotUnderstood do: [:e | e resume: false]. children do: [:anElement | | found | found := anElement find: aBlock. found ifNotNil: [^ found]]. ^ nil
if there is only one element to be found, the order in which you search for it does not matter. so you can start by scanning the children, which makes it possible to write a simple recursive method:
SoupTag>>find: aBlock
^ children detect: [:anElement | (anElement find: aBlock) notNil] ifNone: [ [(aBlock value: self) ifTrue: [self]] on: MessageNotUnderstood do: [nil]].
now I must say your overall design seems to me very complex and really overusing the DNU mechanism. it should be possible to do what you want in a much simpler way, but since I don't know what you want to implement exactly I will not elaborate on this.
regards,
Stef
SoupTag>>find: aBlock
^ children detect: [:anElement | (anElement find: aBlock) notNil] ifNone: [ [(aBlock value: self) ifTrue: [self]] on: MessageNotUnderstood do: [nil]].
I just realized this code is wrong, since it can only return a direct children, not a grandchildren (if your children have children themselves..)
Stef
Hi Stéphane,
Stéphane Rollandin wrote:
hello,
SoupTag>>doesNotUnderstand: aMessage (aMessage arguments size = 0) ifFalse: [^ super doesNotUnderstand: aMessage]. ^ attributes at: aMessage selector ifAbsent: [super doesNotUnderstand: aMessage]
this can be simpler, since the dictionary lookup will not confuse #id with #id:, so you can get rid of the arguments size test:
Agreed, thanks.
if there is only one element to be found, the order in which you search for it does not matter.
There could be many and order matters. This method is really findFirst, but I'm trying to keep the names analogous to the library I'm porting.
now I must say your overall design seems to me very complex and really overusing the DNU mechanism. it should be possible to do what you want in a much simpler way, but since I don't know what you want to implement exactly I will not elaborate on this.
The goal is to be able to concisely specify complex find: queries without having to worry about whether a tag has an attribute. This shouldn't mean that a tag swallows messages all the time.
A tag may represent a structure like:
<p class="outer"> <p id="1">ID 1</p> <p class="A">CLASS A <p blah="blah" id="1">BLAH 1</p> <p blah="blah" class="A">BLAH 2</p> </p> </p>
Where each p is a tag, and nested p's are children. To find the BLAH 2:
blah2 = tag find: [:each | each blah = 'blah' and: [each class = 'A']]
Each tag in the hierarchy before the desired element will throw an MNU when an attribute is missing. This is desired, i.e.:
blah2 blah " blah" (blah2 attributeAt: 'class') " A " blah2 id " should signal an MNU "
Now, maybe catching the MNU is not the right way to do this but I'm not sure how else to do it while leaving the syntax so concise.
Thanks, Zulq.
On Fri, 19 Dec 2008 10:51:01 +0100, Zulq wrote:
Hi All,
Perhaps I am misunderstanding the behaviour of
I have a class SoupTag which holds a dictionary of attributes and a collection of children which are also soup tags.
As a shorthand for attribute access, SoupTag implements:
...
But all I get is infinite recursion from the doesNotUnderstand. I think this should work as this little test demonstrates:
[('abc' + 1) + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " prints 2 "
Nah, the result has nothing to do with #on:do: resuming with 1, you better try
[('abc' + 1) + 1] on: MessageNotUnderstood do: [:e | e resume: -1]
which still says 2. This because someone, behind you back, put #asNumber arithmethic into ByteString ... now this attempts (Number readFrom: 'abc') which gives 0 for your +1 +1 and so 2.
You may want to start DNU testing with ('abc' break; + 1) and then see where it goes.
HTH.
/Klaus
Any help is greatly appreciated.
Thanks, Zulq.
Hi Klaus,
Klaus D. Witzel wrote:
Nah, the result has nothing to do with #on:do: resuming with 1, you better try
[('abc' + 1) + 1] on: MessageNotUnderstood do: [:e | e resume: -1]
which still says 2. This because someone, behind you back, put #asNumber arithmethic into ByteString ... now this attempts (Number readFrom: 'abc') which gives 0 for your +1 +1 and so 2.
You may want to start DNU testing with ('abc' break; + 1) and then see where it goes.
Hmm... I think something is not right or at the very least the semantics are subtly different than I expect.
VisualWorks: [Object new blah + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " = 2 "
[MessageNotUnderstood signal + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " = 2 "
Squeak: [Object new blah + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " infinite recursion!!! "
[MessageNotUnderstood signal + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " = 2 "
If I look at doesNotUnderstand: in both I see that in VW the resumed value is returned. In Squeak is is not... surely this can't be right?
As for my problem, I think a simpler solution is to pass an adaptor/proxy object to the block rather than the tag itself. This adaptor can then marshal behaviour such that it will act as a message eating null if it receives an MNU from the tag it's looking after.
Thanks, Zulq.
Hi Zulq, I made sure this was fixed in VisualWorks. Steve Dahl and I fixed this together. Here's an analogous fix for Squeak. The essential change is to make Object>>doesNotUnderstand: check if the MessageNotUnderstood exception was handled or not, so
MessageNotUnderstood new message: aMessage; receiver: self; signal. ^ aMessage sentTo: self.
is replaced with
(exception := MessageNotUnderstood new) message: aMessage; receiver: self. resumeValue := exception signal. ^exception reachedDefaultHandler ifTrue: [aMessage sentTo: self] ifFalse: [resumeValue]
HTH
On Fri, Dec 19, 2008 at 8:13 AM, Zulq Alam me@zulq.net wrote:
Hi Klaus,
Klaus D. Witzel wrote:
Nah, the result has nothing to do with #on:do: resuming with 1, you better try
[('abc' + 1) + 1] on: MessageNotUnderstood do: [:e | e resume: -1]
which still says 2. This because someone, behind you back, put #asNumber arithmethic into ByteString ... now this attempts (Number readFrom: 'abc') which gives 0 for your +1 +1 and so 2.
You may want to start DNU testing with ('abc' break; + 1) and then see where it goes.
Hmm... I think something is not right or at the very least the semantics are subtly different than I expect.
VisualWorks: [Object new blah + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " = 2 "
[MessageNotUnderstood signal + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " = 2 "
Squeak: [Object new blah + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " infinite recursion!!! "
[MessageNotUnderstood signal + 1] on: MessageNotUnderstood do: [:e | e resume: 1] " = 2 "
If I look at doesNotUnderstand: in both I see that in VW the resumed value is returned. In Squeak is is not... surely this can't be right?
As for my problem, I think a simpler solution is to pass an adaptor/proxy object to the block rather than the tag itself. This adaptor can then marshal behaviour such that it will act as a message eating null if it receives an MNU from the tag it's looking after.
Thanks, Zulq.
Hi Eliot,
Eliot Miranda wrote:
Hi Zulq,
I made sure this was fixed in VisualWorks. Steve Dahl and I fixed
this together. Here's an analogous fix for Squeak.
Thanks for the fix.
I've reported the issue in mantis [1], uploaded a unit test and the fix you attached.
Is it OK to use this fix since it's from a commercial product? Or will someone need to develop a fix who hasn't seen this or the original code.
- Zulq
On Mon, Dec 22, 2008 at 8:59 AM, Zulq Alam me@zulq.net wrote:
Hi Eliot,
Eliot Miranda wrote:
Hi Zulq,
I made sure this was fixed in VisualWorks. Steve Dahl and I fixed this together. Here's an analogous fix for Squeak.
Thanks for the fix.
I've reported the issue in mantis [1], uploaded a unit test and the fix you attached.
Is it OK to use this fix since it's from a commercial product? Or will someone need to develop a fix who hasn't seen this or the original code.
I wrote the fix I posted in response to your post. It is not identical to the VW code, but it is essentially the same solution. The solution is pretty obvious, so I don't think there will be any issues.
- Zulq
I highly recommend some summary of this licensing discussion be included in the bug report.
Ken
On Mon, 2008-12-22 at 11:49 -0800, Eliot Miranda wrote:
On Mon, Dec 22, 2008 at 8:59 AM, Zulq Alam me@zulq.net wrote: Hi Eliot,
Eliot Miranda wrote: Hi Zulq, I made sure this was fixed in VisualWorks. Steve Dahl and I fixed this together. Here's an analogous fix for Squeak. Thanks for the fix. I've reported the issue in mantis [1], uploaded a unit test and the fix you attached. Is it OK to use this fix since it's from a commercial product? Or will someone need to develop a fix who hasn't seen this or the original code.
I wrote the fix I posted in response to your post. It is not identical to the VW code, but it is essentially the same solution. The solution is pretty obvious, so I don't think there will be any issues.
- Zulq [1] http://bugs.squeak.org/view.php?id=7250
OK, done.
Thanks for all the responses, everyone.
Zulq
Ken Causey wrote:
I highly recommend some summary of this licensing discussion be included in the bug report.
Ken
On Mon, 2008-12-22 at 11:49 -0800, Eliot Miranda wrote:
On Mon, Dec 22, 2008 at 8:59 AM, Zulq Alam me@zulq.net wrote: Hi Eliot,
Eliot Miranda wrote: Hi Zulq, I made sure this was fixed in VisualWorks. Steve Dahl and I fixed this together. Here's an analogous fix for Squeak. Thanks for the fix. I've reported the issue in mantis [1], uploaded a unit test and the fix you attached. Is it OK to use this fix since it's from a commercial product? Or will someone need to develop a fix who hasn't seen this or the original code.
I wrote the fix I posted in response to your post. It is not identical to the VW code, but it is essentially the same solution. The solution is pretty obvious, so I don't think there will be any issues.
- Zulq [1] http://bugs.squeak.org/view.php?id=7250
squeak-dev@lists.squeakfoundation.org