The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Isotropic Selectors

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
James Robertson

Posts: 29924
Nickname: jarober61
Registered: Jun, 2003

David Buck, Smalltalker at large
Isotropic Selectors Posted: Jun 17, 2004 4:10 AM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Isotropic Selectors
Feed Title: Travis Griggs - Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/travis-rss.xml
Feed Description: This TAG Line is Extra
Latest Agile Buzz Posts
Latest Agile Buzz Posts by James Robertson
Latest Posts From Travis Griggs - Blog

Advertisement
Made any Rectangles lately? Is it left:right:top:bottom:? or is it top:bottom:left:right? or top:left:bottom:right:? LayoutFrames are even funner. Any time you get these long multiple arguments message, you have candidates for these keyword lists where the order isn't really important.

I've only played with Lisp a little, but I remember one of the cool things you could do was list the keywords in any order you wanted. Something like (Point y: 1 x: 4) (it's been a while so forgive me if that's not exactly right). What would it take to have the same ease and flexibility in Smalltalk?

doesNotUnderstand: comes to the rescue one again! Anytime you mess with dnu:, want to build (and test) the facilities first, saving the hacking of dnu: till the end. There's a couple methods that come into play here, we'll go one by 1.

Unique Keywords

We need a way of determining whether a method signature is even a candidate for keyword rearrangement. To be so, each of its keywords must be unique. We can keywords to a symbol to get an Array of the different keywords. We could just send keywords asSet size = keywords size, but that seemed computationaly expensive, so I implemented:

SequenceableCollection>>hasUniqueElements
1 to: self size - 1
		do: 
			[:n | 
			| candidate |
			candidate := self at: n.
			n + 1 to: self size do: [:m | (self at: m) = candidate ifTrue: [^false]]].
	^true

It's about 15x faster than the one liner.

Unique Keywords

The next part is being able to determine if two selectors are "isotropic". I think I can use that term, if not, I'm sure someone will correct me. Basically we want to be able to detect that x:y: and y:x: are the same selectors, but with different keyword ordering. We can extend any class, we want, so how about Symbol.

Symbol>>isotropicMatch: aSymbol 
	"aSymbol is assumed to be multi and and keyword unique"

	| mine his |
	self size = aSymbol size ifFalse: [^false].
	self last = $: ifFalse: [^false].
	mine := self keywords.
	his := aSymbol keywords.
	SequenceableCollectionSorter sort: mine.
	SequenceableCollectionSorter sort: his.
	^mine = his

We want this one to go fast too. We're going to be scanning ALL of a given receivers selectors, so we want it to resolve quickly. The first two lines of the method are quick and get rid of almost all match candidates. We only have to run the last 5 lines on rare cases, almost always on a match.

Having this code, we can make sure that #x:y: isotropicMatch; #y:x: returns true, and #x:a: isotropicMatch: #x:y: does not.

Hack it in

This could probably be factored better. You have to do some of the work in the existing Object>>doesNotUnderstand: method though, because you want to return from it. One of the cool things I noticed doing this is that you can override a method in <None> When you're done, you just unload <None> and everything goes back to normal. Basically, we want to extend the default doesNotUnderstand: message so that it first checks to see if it's just an order mangled version of something it could understand, and if so, do so. Bolting this code

	aMessage arguments size > 1 
		ifTrue: 
			[(self findIsotropicSelector: aMessage selector) ifNotNil: 
					[:isoSelector | 
					| argMap |
					argMap := Dictionary new.
					aMessage selector keywords with: aMessage arguments
						do: [:a :b | argMap at: a put: b].
					^self perform: isoSelector
						withArguments: (isoSelector keywords collect: [:each | argMap at: each])]].

to the front of Object>>doesNotUnderstand: and add this supporting method:

findIsotropicSelector: aSelector 
	aSelector keywords hasUniqueElements ifFalse: [^nil].
	^self class allSelectors detect: [:each | each isotropicMatch: aSelector]
		ifNone: [nil]

and it should work. The helper method enumerates the receiver's selectors looking for an isotropic match. The preamble to dnu: uses it to to determine if there's an isotropic equivalent, and if so, reorders the arguments with a map, and resends.

The Result

This is kind of fun. (Point y: 3 x: 5) = (5 @ 3) returns true! Of course, Rectangle top: 4 bottom: 6 left: 1 right: 3 prints as "1@4 corner: 3@6". You don't have to stick to class side instance creation methods either. You can do (Array new: 1) put: 'hi' at: 1! I don't know, I think that's kind of cool.

Read: Isotropic Selectors

Topic: Ray tracing competition results Previous Topic   Next Topic Topic: Sharing Smalltalk Extensions

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use