<?xml version='1.0' encoding='UTF-8' ?>
<rss version="2.0" xmlns:admin="http://webns.net/mvcb/" xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:icbm="http://postneo.com/icbm" xmlns:includedComments="http://www.laudably.com/rss2-comments" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
	<channel>
		<title>Smalltalk Tidbits, Industry Rants</title>
		<link>http://www.cincomsmalltalk.com/blog/blogView</link>
		<description>Cincom Product Manager</description>
		<webMaster>jrobertson@cincom.com</webMaster>
		<lastBuildDate>Wed, 18 Oct 2006 16:42:43 EDT</lastBuildDate>
		<image>
			<url>http://www.cincomsmalltalk.com/images/cst_small.jpg</url>
			<title>Smalltalk Tidbits, Industry Rants</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView</link>
			<height>50</height>
			<width>81</width>
		</image>
		<admin:generatorAgent rdf:resource="http://www.cincomsmalltalk.com/CincomSmalltalkWiki/Silt"></admin:generatorAgent>
		<admin:errorReportsTo rdf:resource="mailto:jrobertson@cincom.com"></admin:errorReportsTo>
		<dc:language>en-us</dc:language>
		<dc:creator>James A. Robertson</dc:creator>
		<dc:rights>Copyright 2005 Cincom Systems, Inc.</dc:rights>
		<dc:date>2006-10-18T16:42:43-05:00</dc:date>
		<icbm:latitude>39.214103</icbm:latitude>
		<icbm:longitude>-76.878807</icbm:longitude>
		<item>
			<title>About the code generation post...</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3338642518</link>
			<category>examples</category>
			<pubDate>Wed, 18 Oct 2006 16:41:58 EDT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">

<p>I <a href="http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3338622442">commented</a> on a &quot;Java dynamic code&quot; post earlier, and got a few comments - so I pushed up a <a href="http://www.cincomsmalltalk.com/casts/generating_st_code.html">screencast</a> showing how to generate new code (methods and classes) at runtime in Smalltalk. It's way, way simpler than the Java example, and I show that in the screencast. Watch it <a href="http://www.cincomsmalltalk.com/casts/generating_st_code.html">here;</a> enjoy.</p>
<!-- technorati tags start --><p style="text-align:right;font-size:10px;">Technorati Tags: 
<a href="http://www.technorati.com/tag/java" rel="tag">java</a>, <a href="http://www.technorati.com/tag/smalltalk" rel="tag">smalltalk</a>, <a href="http://www.technorati.com/tag/dynamic languages" rel="tag">dynamic languages</a></p><!-- technorati tags end -->
</div>]]></description>
			<guid isPermaLink="false">3338642518</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3338642518</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3338642518</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3338642518</wfw:comment>
		</item>
		<item>
			<title>On the fly Updating in Cincom Smalltalk</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3324276899</link>
			<category>examples</category>
			<pubDate>Fri, 05 May 2006 10:14:59 EDT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">

<p>I've alluded to the patching capabilities of <a href="http://www.cincomsmalltalk.com/BottomFeeder">BottomFeeder</a> before, but it seems that I've never actually gone into much detail. I had an email on that this morning, so I figured I should post on it. </p>
<p>The basic capabilities are built into the product - assuming you've left the compiler in your runtime, loading new code in via file-in or parcel loading is easily possible. What I added for my application was this:</p><ul xmlns="http://www.w3.org/1999/xhtml">
			<li>An HTTP based interface, allowing the application to query a server for updates</li>
		<li>an XML based manifest system whereby the client can check what's already loaded versus what's on the server</li><li>An ability to have the updates loaded after download, without the normal development-time dialogs</li></ul><p>If you have access to the <a href="http://www.cincomsmalltalk.com/CincomSmalltalkWiki/Public+Store+Repository">Public Store Repository,</a> you can check out the package <strong>PatchFileDelivery</strong> (which should have no dependencies on BottomFeeder - I may have to weed a couple out). The name is something of a misnomer, due to the evolution of the package. When I started, I was delivering small patch parcels, but I moved away from that and on to delivery of new versions of already loaded parcels - it made version control in the runtime a lot simpler. The basic steps look like this:</p><ol xmlns="http://www.w3.org/1999/xhtml">
			<li>Execute an HTTP Query to the server for the XML manifest</li>
		<li>Client compares Manifest to what's loaded</li><li>Client offers any available updates to the user</li><li>Selected updates are downloaded via HTTP</li><li>If requested (and if possible), updates are loaded immediately</li></ol><p>So let's take a brief look at those steps. The manifest is a collection of <strong>ComponentDefinition</strong> objects. That class looks like this:</p>

<p><pre>

Smalltalk.Patch defineClass: #ComponentDefinition
	superclass: #{Core.Object}
	indexedType: #none
	private: false
	instanceVariableNames: 'parcelName parcelFilename version oldVersion releaseDate vwVersion isPlugin descriptiveName description fileSize allowDynamicLoad '
	classInstanceVariableNames: ''
	imports: ''
	category: 'PatchFileDelivery'

</pre></p><p>The important pieces of that are the <em>version,</em> <em>parcelName,</em> and <em>allowDynamicLoad.</em> The last one of those is a flag to the client - if it's false, the component in question requires a restart. That comes up when I have an update that does major changes to the UI, for instance. There are ways of dealing with that, but I figured a restart was simpler, and haven't really received complaints. The version is just that - a value derived from Store, the source file repository I use. The name and version are compared to what's loaded to come up with the list for the user. </p><p>Once that's figured out, the user's selections are downloaded via HTTP. The only difference between the base HTTP capabilities of VW and what I do is the progress dialog - and that's code that was submitted by <a href="http://www.cincomsmalltalk.com/userblogs/bobw/blogView">Bob,</a> one of our engineers. The change? Additional code in a subclass of the relevant HTTP class to raise notifications of status. Once the code is downloaded, it's either simply saved, or saved and loaded. If it's the latter, the following code gets used to load the new version of the parcel:</p>

<p><pre>

actuallyLoadParcelFrom: parcelFile

	[[Parcel loadParcelFrom: parcelFile] on: Parcel parcelAlreadyLoadedSignal, CodeStorageError
		do: [:ex | ex resume: true]] 
			on: DuplicateBindingsError
			do: [:ex | ex resume]

</pre></p><p>The first handler catches the &quot;already loaded&quot; signal - which normally raises a dialog. I didn't want that, so I catch it and just have the system resume with true. Which illustrates one of the cool things about Smalltalk exception handling, btw - the ability to rewind back and have the system move along with the correct answer.</p><p>The second handler catches transient errors that arise during the load of the new parcel - in some situations, the new version of code can look like a duplicate code binding. That gets resolved as the load continues, so I just catch it and continue. Which again demonstrates the coolness of Smalltalk exception handling.</p><p>Once that's done, we have the new code loaded and are ready to run again. What about the next startup? Well, BottomFeeder looks in a known directory for new versions of code, and that's where the upgrade manager saves them. So when the application is started up, it does step (5) from above. And that's it - pretty simple.</p></div>]]></description>
			<guid isPermaLink="false">3324276899</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3324276899</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3324276899</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3324276899</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3324276899</includedComments:puid>
					<includedComments:author>Isaac Gouy</includedComments:author>
					<includedComments:pubDate>2006-05-07T20:36:56-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;&lt;a href="http://www.cs.umd.edu/~mwh/papers/ginseng.pdf"&gt;Practical Dynamic Software Updating for C&lt;/a&gt;. Iulian Neamtiu, Michael Hicks, Gareth Stoyle, and Manuel Oriol. In Proceedings of the ACM Conference on Programming Language Design and Implementation (PLDI), June 2006. To appear.
&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title>and in C</includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3324276899</wfw:comment>
		</item>
		<item>
			<title>Flexible Exception Handling</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3321788777</link>
			<category>examples</category>
			<pubDate>Thu, 06 Apr 2006 15:06:17 EDT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">

<p>I get asked about Smalltalk exception handling from time to time, and - specifically - I get asked how it differs from what's done in Java. The primary difference is in how the context stack is handled. In Java, when you get to the handler code, the stack has been unwound and is just <em>gone.</em> Not so in Smalltalk - as a matter of fact, <em>the stack is an argument held in the exception.</em> Here's a simple example - I'll use the <strong>NetResources</strong> library to try and retrieve a non-existant url, and toss a breakpoint into the handler code so you can see what's going on. Here's the relevant code:</p>
<p><pre>

	response := [client executeRequestDo: 
					[:connection | client getNotifyingResponse: connection]]
		on: (self class httpExceptions, Error) 
		do: [:ex | self behaviourForException: ex. nil].

</pre></p><p>We've wrapped the actual HTTP request in a handler that sends all exceptions to a method called #behaviorForException:. That's done so that we can respond appropriately based on the kind of exception that crops up. Here's that method:</p>

<p><pre>

behaviourForException: ex
	ex class = Security.SSLBadCertificate
		ifTrue: [Security.X509.X509Registry default addCertificate: ex parameter parameter].
	(self class possibleTimeoutExceptions includes: ex class) 
		ifTrue: [self updateCacheResponseCodeOnly.
				^self class triggerTimeoutEvent: url].
	(ex isResumable and: [self class exceptionsWeShouldResume includes: ex class] ) 
		ifTrue: [ex resume]
		ifFalse: [self reportTheErrorType: ex]

</pre></p>

<p>See that part at the bottom that checks for resumable (and worth resuming) exceptions?  If we get there, what will happen is simple - the system will return to the point where the exception got thrown, and simply proceed as if it hadn't happened.  You might ask yourself, why would we want to do that? As it happens, there's code in the calling method to handle things like HTTP redirects and Authorization requests - so those exceptions are simply resumed.  So anyway, a brief demonstration - here's a screen shot of an attempt to fetch a non-existant URL:</p> 

<p><img alt="Debugger on 404" src="http://www.cincomsmalltalk.com/blog/images/examples/debug_exception.png"/></p>

<p>Now, here's an inspector on the exception:</p>

<p><img alt="Inspector on the Context" src="http://www.cincomsmalltalk.com/blog/images/examples/debug_context.png"/></p>

<p>And drilling down, the context itself:</p>

<p><img alt="Inspector on the Context" src="http://www.cincomsmalltalk.com/blog/images/examples/debug_context2.png"/></p>
<p>All of which shows how it can be useful to have access to the full stack in a handler. resuming isn't the only thing you can do, either - you can have the exception return to the (original) caller with some default value, you can resend the exception (or another) - it's pretty wide open. </p></div>]]></description>
			<guid isPermaLink="false">3321788777</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3321788777</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3321788777</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3321788777</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3321788777</includedComments:puid>
					<includedComments:author>Martin Kobetic</includedComments:author>
					<includedComments:pubDate>2006-04-06T16:29:48-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;This is thoroughly off topic, but I feel I have to warn potential victims that might try to use what they see here. SSL.BadCertificate exception means that the certificate presented by the server failed validation for some reason. Adding such certificate to the collection of trusted certificates in the default X509Registry as a default action is, er, not the right thing to do. I understand that the motivation here is likely to populate the registry (which is initially empty) as the client connects to various sites, which might be acceptable in *some* circumstances, but even then there should be at least some explicit confirmation from the user or something. Otherwise you are completely defeating authentication, you may as well use plain http instead of https.
Also the "trusted" certificates in the registry should be CA certificates, not server certificates. The SSLBadCertificate exception is actually a substitute for several X509 exceptions (see SSLContext&gt;&gt;validateCertificateChain:for:). In case of something like X509.RootNotTrusted the 'ex parameter parameter' exception will give you a CA certificate. However if it's something like X509.BadCertificate triggered by invalid signature or expired certificate somewhere in the middle of the certificate chain, you'll get exactly that broken certificate. Definitely not something you want to trust, ever.
Anyway, my main point is that, yes this handler will suppress those pesky "RootNotTrusted" errors, but these are serious security warnings, and you've got to be careful about how you handle these things. Especially in framework code like NetResources.
&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title>SSLBadCertificate is serious!</includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3321788777</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3321788777</includedComments:puid>
					<includedComments:author>Hummus and Magnets</includedComments:author>
					<includedComments:pubDate>2006-04-08T18:08:52-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;Trackback from Hummus and Magnets

&lt;a href="http://blog.quenta.org/2006/04/exceptions.html"&gt;Exceptions&lt;/a&gt;

...
&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title>Exceptions</includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3321788777</wfw:comment>
		</item>
		<item>
			<title>Smalltalk compared</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</link>
			<category>examples</category>
			<pubDate>Sun, 01 Jan 2006 14:06:10 EST</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml"> 
<p> 
<a href="http://chronos-st.blogspot.com/"> Alan Lovejoy</a> pointed
me 
<a href="http://www-128.ibm.com/developerworks/library/j-ruby/?ca=dgr-lnxw01RubyOffRails"> 
at a page that compares Java and Ruby,</a> and suggested that I
provide Smalltalk examples. The Smalltalk is going to be a lot like
the Ruby code - both are dynamic languages with what people now
call &quot;duck typing&quot;.</p> 
<p> The page sets up a simple example with a pair of classes - Word
and Definition:</p> 
<p> 
<img alt="Class Definitions" src="http://www.cincomsmalltalk.com/blog/images/examples/class_def.png"></img> 
 
</p> 
<p> You can go to the linked site to see the Java and Ruby classes -
here are the class definitions in Smalltalk:</p> 
<p> 
<pre> 

Smalltalk.Words defineClass: #Word
	superclass: #{Core.Object}
	indexedType: #none
	private: false
	instanceVariableNames: 'spelling partOfSpeech definitions synonyms
'
	classInstanceVariableNames: ''
	imports: ''
	category: 'Words'

Smalltalk.Words defineClass: #Definition
	superclass: #{Core.Object}
	indexedType: #none
	private: false
	instanceVariableNames: 'word definition exampleSentence '
	classInstanceVariableNames: ''
	imports: ''
	category: 'Words'


</pre> 
</p> 
<p> In Ruby, it looks like you can define getters/setters in the
class definition. In Cincom Smalltalk, the environment does the
same thing for you, offering to define getters/setters (and a
default initializer) as part of creating the class. So in step one,
we get a small bit further than Ruby, due to the tools we have. As
to the methods, let's start with the initiazers - I had to modify
the default initializer so that it matched the code in the example
page - first 
<strong> Definition,</strong> then 
<strong> Word:</strong> </p> 
<p> 
<pre> 


initialize
	&quot;Initialize a newly created instance. This method must answer the
receiver.&quot;

   word := nil.
	definition := nil.
	exampleSentence := Set new.

initialize
	&quot;Initialize a newly created instance. This method must answer the
receiver.&quot;

   spelling := nil.
	partOfSpeech := nil.
	definitions := Set new.
	synonyms := Set new.


</pre> 
</p> 
<p> So on to the meat - the tools mostly created what I needed, and
I just had to modify the defaults. The class definitions have a lot
of things we don't need to worry about right now - I created them
via the class creation wizard, seen below:</p> 
<p> 
<img alt="Smalltalk Class Defining" src="http://www.cincomsmalltalk.com/blog/images/examples/smalltalk_class_def.png"></img> 
 
</p> 
<p> That wizard removes a lot of the typing drudgery of class
creation - mind you, old hands (like me) can still do it the &quot;old
fashioned way&quot; in the browser. Let's define the #addDefinition: and
#addSynonym: methods now - they auto-check for duplicates by being
Set objects: </p>
<p> 
<pre> 

addDefinition: definitionString
	self definitions add: definitionString.

addSynonym: synonymString
	self synonyms add: synonymString.


</pre> 
</p> 
<p> Now creating a new instance is easy - we create a class side
convenience method for creating new words::</p> 
<p> 
<pre> 

newWord: wordString partOfSpeech: partOfSpeechString
	^self new
	       spelling: wordString;
	       partOfSpeech: partOfSpeechString.


</pre> 
</p> 
<p> Some explanation - the #new method creates the new object and the #spelling: setter is immediately sent to that. The semi-colon is a cascade, which allows us to send the #partOfSpeech: setter to the same object as the first message went to. Note the name of the method: #newWord:partOfSpeec:. It's <em>self describing</em>. Instead of #new, we can create our own class creation protocol that is self explanatory. Now to use it:</p> 
<p> 
<pre> 

&quot;Create a Word&quot;
word := Word newWord: 'ebullient' partOfSpeech: 'adjective'.
word addDefinition: 'Overflowing with Enthusiasm'.
word addDefinition: 'Boiling up or over'.


</pre> 
</p> 
<p> Notice how clear that is - and how much clearer it is than the Java example on that page (IMHO, it's clearer than Ruby, simply because of the keyword message). Keyword messages make it possible to <em>make your code very intention revealing</em> - which is a good thing. This is part of why Smalltalkers tend to send you to the source instead of to some doc - because the source (if done decently) is documentation. Yes, you can write bad Smalltalk, and I've done plenty of that myself :)</p> 
<p> If you look at the explanation of collection protocol on that page, everything he says about Ruby's collections applies to Smalltalk. We can add things into the collections without fear of them blowing up. In fact, if we make sure that the things we add are polymorphically (i.e., message signature) identical to each other, it doesn't matter what they are at all. I take great advantage of that in <a href="http://www.cincomsmalltalk.com/BottomFeeder">BottomFeeder.</a></p> 
<p>Moving past the example, the linked page goes into Ruby iteration. We have the same power in Smalltalk - we can iterate over any kind of collection like this:</p>

<p><pre>

someCollection do: [:each | each doSomethingHere]. 

</pre></p>

<p>The [ ] syntax is for a closure - the first place you'll find them in Smalltalk is in the logical operations (ifTrue/ifFalse, etc). They provide a lot more power though, and the fact that they are used to define the common operations (doWhile, et. al.) is telling - <em>those operations are not reserved word syntax in Smalltalk - they are messages.</em> Which means that you can define your own versions. I've seen plenty of people add #do: to class Object so that any object can be treated like a collection, for instance. </p> <p>The entire discussion of duck typing applies to Smalltalk as well. Rather than formal interfaces, Smalltalkers worry about polymorphic equivalence. You can implement a matching protocol between any kind of objects that make sense, and then use them together. A common example used in intro classes is a FinancialInstrument - without regard to inheritance, just define a financial protocol amongst all the objects, and then use it - for instance, a #currentValue method might determine what an instrument is worth right now - and be very different for various objects that share little else. Even so, they can all be placed in a collection, and current worth calculated like this:</p>

<p>
<pre>

instruments inject: 0 into: [:subTotal :next | subTotal + next currentValue].

</pre></p>

<p>The comment for #inject:into:, since it may not be clear to non-Smalltalkers:</p>

<p><em>Accumulate a running value associated with evaluating the argument,
	binaryBlock, with the current value and the receiver as block arguments. 
	The initial value is the value of the argument, thisValue.</em></p><p>That pretty much covers what the IBM page went into. The main difference you're going to see in Smalltalk is that it's not file-oriented. You work in an image, and you create code in a browser. You can save packages out into loadable modules though (we call them parcels here at Cincom) - and this server is fired up exactly that way. I have a basic image which starts, grabs a set of parcels, loads them, configures itself as a set of post-load actions, and then goes. Interested? Grab the <a href="http://smalltalk.cincom.com/downloads/index.ssp">Cincom Smalltalk non-commercial here.</a></p></div>]]></description>
			<guid isPermaLink="false">3313577170</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3313577170</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3313577170</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:puid>
					<includedComments:author>Isaac Gouy</includedComments:author>
					<includedComments:pubDate>2006-01-02T01:34:45-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;James &lt;em&gt;The Smalltalk is going to be a lot like the Ruby code&lt;/em&gt;&lt;br/&gt;
As the "Ruby off the Rails" article states "Ruby supports default values for parameters" &lt;strong&gt;but Smalltalk doesn't&lt;/strong&gt; - so we need 2 additional class creation methods for Word and 1 additional class creation method for Definition (&lt;strong&gt;just like the Java examples&lt;/strong&gt;) before we've provided something like the Ruby code.&lt;br/&gt;&lt;br/&gt;

As the "Ruby off the Rails" article states "Ruby supports a shortcut notation for defining properties" &lt;strong&gt;but Smalltalk doesn't&lt;/strong&gt; so we need 11 explicit accessor methods (&lt;strong&gt;just like the Java example&lt;/strong&gt;) - and, of course, Java IDEs automate accessor creation also.&lt;br/&gt;&lt;br/&gt;

James &lt;em&gt;they auto-check for duplicates by being Set objects&lt;/em&gt;&lt;br/&gt;
Although both Java and Ruby provide Hash Set functionality, the "Ruby off the Rails" article uses the equivalent of OrderedCollection in both the Java and Ruby examples - so comparable Smalltalk would use OrderedCollection not Set.&lt;br/&gt;&lt;br/&gt;


James &lt;em&gt;everything he says about Ruby's collections applies to Smalltalk&lt;/em&gt;&lt;br/&gt;
As the "Ruby off the Rails" article states "Ruby's collection handling... access members (via position) -- and do so without the fear of things blowing up on you!" &lt;strong&gt;but Smalltalk doesn't&lt;/strong&gt; - the equivalent to the Ruby example Listing 6 &lt;strong&gt;will blow-up&lt;/strong&gt; with a Subscript out of bounds: exception!
&lt;pre&gt;
| ndef | 
ndef := OrderedCollection with: #idef_1 with: #idef_2 with: #idef_3 with: #idef_4.
ndef at: 9

Unhandled exception: Subscript out of bounds: 
OrderedCollection(Object)&gt;&gt;subscriptBoundsErrorFor:index:
OrderedCollection&gt;&gt;at:
&lt;/pre&gt;
 
&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title>but Smalltalk doesn't</includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:puid>
					<includedComments:author>
James Robertson</includedComments:author>
					<includedComments:pubDate>2006-01-02T11:30:32-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;Comment by 
James Robertson&lt;/p&gt;

&lt;p&gt;


&lt;p&gt;Isaac,&lt;/p&gt;
&lt;p&gt;I noted in the post that I had to write the instance creation method. I also noted that I thought the keyword nature of the method made it nicer, but YMMV. As to the setters/getters - readers who pay attention will notice that I explained that they don't get created via the shorthand method Ruby uses - instead, the tools generate them for you (or offer to). Same result, same lack of having to type them. &lt;/p&gt;&lt;p&gt;As to the out of bounds exception, I probably should have mentioned stream protocol, which is more similar to what the Ruby code was doing.&lt;/p&gt;&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title>
Trolls</includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:puid>
					<includedComments:author>Isaac Gouy</includedComments:author>
					<includedComments:pubDate>2006-01-02T14:52:35-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;"Ruby supports default values for parameters" &lt;strong&gt;but Smalltalk doesn't&lt;/strong&gt; so we need additional class creation methods (just like Java).&lt;br/&gt;&lt;br/&gt;

"Ruby supports a shortcut notation for defining properties" &lt;strong&gt;but Smalltalk doesn't&lt;/strong&gt; so we need explicit accessor methods (just like Java) - comparing Ruby to Smalltalk we can see that "Ruby's syntax is quite terse".&lt;br/&gt;&lt;br/&gt;

Here's a Smalltalk listing for &lt;a href="http://www-128.ibm.com/developerworks/library/j-ruby/?ca=dgr-lnxw01RubyOffRails"&gt;comparison with Listings 1,2&amp;3&lt;/a&gt;.&lt;br/&gt;

&lt;pre&gt;
Smalltalk defineClass: #Word
   superclass: #{Core.Object}
   indexedType: #none
   private: false
   instanceVariableNames: 'spelling partOfSpeech definitions synonyms '
   classInstanceVariableNames: ''
   imports: ''
   category: 'Dictionary'

"class methods"
spelling: aSpelling partOfSpeech: aPartOfSpeech
   ^(super new) initialize
      spelling: aSpelling; 
      partOfSpeech: aPartOfSpeech

spelling: aSpelling partOfSpeech: aPartOfSpeech definitions: aCollection
   | newWord |
   newWord := self spelling: aSpelling partOfSpeech: aPartOfSpeech.
   ^aCollection isNil
      ifTrue: [newWord] 
      ifFalse: [newWord initializeDefinitions: aCollection]

spelling: aSpelling partOfSpeech: aPartOfSpeech definitions: aDefinitionCollection synonyms: aCollection
   | newWord |
   newWord := self spelling: aSpelling partOfSpeech: aPartOfSpeech definitions: aDefinitionCollection.
   ^aCollection isNil
      ifTrue: [newWord] 
      ifFalse: [newWord initializeSynonyms: aCollection]


"instance methods"
initialize
   spelling := nil.
   partOfSpeech := nil.
   definitions := OrderedCollection new.
   synonyms := OrderedCollection new.

initializeDefinitions: aCollection
   aCollection do: [:each| each word: self].
   definitions := aCollection

initializeSynonyms: aCollection
   synonyms := aCollection


spelling
   ^spelling

partOfSpeech
   ^partOfSpeech

definitions
   ^definitions

synonyms
   ^synonyms

spelling: aString
   spelling := aString

partOfSpeech: aString
   partOfSpeech := aString

addDefinition: aDefinition
   (aDefinition word ~= self) ifTrue: [aDefinition word: self].
   self definitions add: aDefinition.

addSynonym: aString
   self synonyms add: aString.




Smalltalk defineClass: #Definition
   superclass: #{Core.Object}
   indexedType: #none
   private: false
   instanceVariableNames: 'word definition exampleSentences '
   classInstanceVariableNames: ''
   imports: ''
   category: 'Dictionary'


"class methods"
new: aString
   ^(super new) initialize
      definition: aString

new: aString for: aWord
   ^(self new: aString) word: aWord

new: aString for: aWord examples: aCollection
   | newDefinition |
   newDefinition := self new: aString for: aWord.
   ^aCollection isNil
      ifTrue: [newDefinition] 
      ifFalse: [newDefinition initializeExamples: aCollection]


"instance methods"
initialize
   word := nil.
   definition := nil.
   exampleSentences := OrderedCollection new.

initializeExamples: aCollection
   exampleSentences := aCollection

word
   ^word

definition
   ^definition

exampleSentences
   ^exampleSentences

definition: aString
   definition := aString

word: aWord
   word := aWord

addExampleSentence: aString
"missing from Ruby Listing 3 - given in Java Listing 2"
   self exampleSentences add: aString
&lt;/pre&gt;   
&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title>Programmers</includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:puid>
					<includedComments:author>
Rich Demers</includedComments:author>
					<includedComments:pubDate>2006-01-02T14:53:55-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;Comment by 
Rich Demers&lt;/p&gt;

&lt;p&gt;


&lt;p&gt;I'm not familiar with Ruby, so I make no comment on it, per se, but I do want to note that automatically generating accessors for instance variables is NOT a good idea. Encapsulation is one of the important ideas of object-orientation, and should not be dismissed out-of-hand. It's fine to write specific accessors manually, or request them via some tool, if they part of a class's external interface, but they should not be automatically generated for all variables.&lt;/p&gt;
&lt;p&gt;A confession: I used to create accessors for every instance variable because that made it easier to find all uses of a variable, but then the VisualWorks Smalltalk Refactoring Browser provided a tab that lists all of a class's variables (including inherited variables) and lists the methods that use each variable. This is another example of the tools the Smalltalk IDE provides that obviates the need for linguistic add-ons. In my case, it convinced me to forego the creation of unnecessary accessors. &lt;/p&gt;

&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title>
Automatically generating accessors</includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3313577170</includedComments:puid>
					<includedComments:author>Isaac Gouy</includedComments:author>
					<includedComments:pubDate>2006-01-02T16:49:06-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;James &lt;em&gt;"As to the out of bounds exception..."&lt;/em&gt;&lt;br/&gt;
Ruby is doing it the old-fashioned way, returning a special error value - instead of doing it the &lt;em&gt;modern&lt;/em&gt; way and raising an exception, like Smalltalk, like Java. Maybe Smalltalk and Java are doing the right thing!&lt;br/&gt;&lt;br/&gt;

I'm repeatedly surprised when folk intent on promoting a programming language seem to lack the courage of their convictions.&lt;br/&gt;&lt;br/&gt;

If the &lt;a href="http://www-128.ibm.com/developerworks/library/j-ruby/?ca=dgr-lnxw01RubyOffRails"&gt;Ruby off the Rails&lt;/a&gt; author really believes Ruby is obviously better, why stack the comparison against Java? 
Reproducing the example in Smalltalk made it apparent that the Ruby listing was not written to make the same checks that the author put into the Java listing - all for the sake of a few lines of code.&lt;br/&gt;&lt;br/&gt;
And then the author has to acknowledge that Listing 9 could be &lt;em&gt;"much, much nicer"&lt;/em&gt; using the &lt;em&gt;"new"&lt;/em&gt; Java - the new Java released over a year before the article publication date. 
It's as though he doesn't quite believe that Ruby's
&lt;pre&gt;definitions.each{ |idef| idef.word = self }&lt;/pre&gt;
looks significantly simpler than
&lt;pre&gt;for (Definition idef : definitions) idef.setWord(this);&lt;/pre&gt;          

&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title>stacking the comparison</includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3313577170</wfw:comment>
		</item>
		<item>
			<title>Handling too many exceptions</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3310101971</link>
			<category>examples</category>
			<pubDate>Tue, 22 Nov 2005 08:46:11 EST</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">

<p>Sometimes, being too aggressive about handling exceptions can be worse than not being aggressive enough. Over the last couple of months, <a href="http://www.cincomsmalltalk.com/userblogs/mls/blogView">Michael</a> has been tweaking the <strong>NetResources</strong> library (it's in the public Store) to deal with some locking issues in the caching code. Last month, there was a change made that caused a few problems - it started trying to handle exceptions that it shouldn't. Here's the relevant code snippet:</p>
<p><pre>

	response := [client executeRequestDo: [:connection | client getNotifyingResponse: connection]]
		on: (self class httpExceptions, Error) do: [:ex | self behaviourForException: ex. nil].
	response ifNil: [^self].

</pre></p><p>The #executeRequestDo: message send executes the HTTP request (or not; it actually implements <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html">conditional-get</a>). When you make an HTTP request, any number of bad things can happen - you can get timeouts, other network errors, redirects - if you don't get a response object, you'll get an exception. Some of those exceptions (like redirect) can (and usually should) be resumed - while others (server error) most certainly should not be. Still others - timeouts - can be resumed or restarted, but the decision is an application level issue.</p><p>Note the exceptions being caught - #httpExceptions is a list of http and network level exceptions, and Error is a catch-all. The logic is in #behaviorForException:. The mistake was in the old version of this method, and in the old version of the handling code. In the previous version of the above, the code was catching Error (i.e., pretty much everything, undifferentiated). Here's the handling code:</p>

<p><pre>

behaviourForException: ex
	ex class = Security.SSLBadCertificate
		ifTrue: [Security.X509Registry default addCertificate: ex parameter parameter].
	(self class possibleTimeoutExceptions includes: ex class) ifTrue: [^self class triggerTimeoutEvent: url].
	(ex isResumable and: [self class exceptionsWeShouldResume includes: ex class] ) 
		ifTrue: [ex resume]
		ifFalse: [self reportTheErrorType: ex]

</pre></p><p>What that does is check the sort of exception we got, and then handle it based on that information. The old code just checked whether the exception could be resumed and then did so; that led to situations where <a href="http://www.cincomsmalltalk.com/BottomFeeder">BottomFeeder</a> would report low level socket errors - the code being resumed was in no state to be resumed. The relevant check is not only whether the exception could be resumed, but whether it <em>should</em> be resumed. In this case, that check is a simple check against this list:</p>
<p><pre>

exceptionsWeShouldResume
	&quot;which ones should we actually resume?&quot;

	^Array
		with: Security.SSLBadCertificate
		with: Net.HttpRedirectionError.

</pre></p><p>Note that the handler stuffs the certificate, which allows us to resume. In the original caller (excerpted at the top) there's logic for dealing with a redirect, so that gets dealt with. Other errors are presumed to be transient, and simply reported. For the purposes of an application like BottomFeeder, where we'll try to read a feed every hour (or whatever the interval has been set to), there's no reason not to ignore most errors. The only additional handling - which is done at the feed level - is to check the response to differentiate between a 404 (presumed to be transient) and a 410 (permanently gone). In the latter case, the app automatically disables the feed in question.</p><p>The bottom line is this - you shouldn't mindlessly resume exceptions. It's as sloppy as swallowing MNU errors, and gets you into states that are really, really hard to diagnose.</p></div>]]></description>
			<guid isPermaLink="false">3310101971</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3310101971</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3310101971</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3310101971</wfw:comment>
		</item>
		<item>
			<title>How Class Promise can help</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</link>
			<category>examples</category>
			<pubDate>Thu, 27 Oct 2005 16:07:05 EDT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p><strong>Update:</strong> Fixed the code snippet</p>

<p>One of the slower operations on the blog server right now is a text search - I don't cache all blog entries in memory, and I have the same (OS) process that gets the request fetch all the items in order to index and do the search. That's fairly expensive, and it makes the image unresponsive if it happens at the same priority as everything else.</p>
<p>The solution in VW terms is to have that expensive search take place in another process. The problem? Well, there's the browser on the far end that made the request, and can't deal with having the server fork the request and hand back nothing. Enter class <strong>Promise</strong>. From the comment:</p><blockquote>A Promise represents a value that is being computed by a concurrently executing process. An attempt to read the value of a Promise will wait until the process has finished computing it. If the process terminates with an exception, an attempt to read the value of the Promise will raise the same exception.</blockquote><p>In short, what that means is that you can push an expensive calculation off to another process, and have the one that is waiting for the result just wait for it. In server terms, said process goes into a non-runnable state, which lets other things happen. </p><p>At this point, understanding the VW process model is useful. Processes at the same priority level do not time slice. So, as requests come in from browsers, the server forks off processes at the same priority - and they all compete for the CPU. In general, if they complete quickly or end up waiting on I/O, it all works out ok. The latter is what I needed in this case - I needed to have the process wait until results were ready. Here's the old code:</p>
<p><pre>

	allResults := self 
		actuallySearchFor: searchText 
		inTitle: searchInTitle 
		inText: searchInText.
	^allResults asSortedCollection: [:a :b | a timestamp &gt; b timestamp].

</pre></p><p>Inside that method, the actual search happens, which can be slow. So, I modified it like so:</p>

<p><pre>

	promise := [self 
		actuallySearchFor: searchText 
		inTitle: searchInTitle 
		inText: searchInText] promiseAt: Processor userBackgroundPriority.
	allResults := promise value.
	^allResults asSortedCollection: [:a :b | a timestamp &gt; b timestamp].

</pre></p><p>What that does is set up a process that runs at the given priority, with a Semaphore signalling when results are ready. As a consequence, the value <strong>allResults</strong> isn't produced until that process finishes - and the process waiting for that result goes into a non-runnable state until that happens. Which means that other processes at that priority level don't get starved for CPU as that one munches through the backlog of posts searching.</p><p>Realistically, I need to add a cache here, and I'm in the process of doing that. In the meantime, this pushes an expensive task to the background, and optimizes server responses for everyone else.</p></div>]]></description>
			<guid isPermaLink="false">3307882025</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3307882025</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3307882025</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</includedComments:puid>
					<includedComments:author></includedComments:author>
					<includedComments:pubDate>2005-10-28T05:30:24-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;If you ported the server to Java, you could use Lucene. :)&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title></includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</includedComments:puid>
					<includedComments:author>
James Robertson</includedComments:author>
					<includedComments:pubDate>2005-10-28T07:23:58-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;Comment by 
James Robertson&lt;/p&gt;

&lt;p&gt;


&lt;p&gt;lol&lt;/p&gt;
&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title>
Yeah, there's an idea</includedComments:title>
				</includedComments:comment>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3307882025</includedComments:puid>
					<includedComments:author>Charles Miller</includedComments:author>
					<includedComments:pubDate>2005-10-28T19:50:26-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;&lt;p&gt;Tongue out of cheek for a moment, (that was my comment above -- I forgot to put my name in), Lucene is one of those annoyingly great libraries that, after you've used it, you can't quite imagine coding a serious text-based web application without. &lt;a href="http://wizards-of-os.org/index.php?id=1046&amp;L=3"&gt;Doug Cutting&lt;/a&gt; deserves a medal or something for open-sourcing it.&lt;/p&gt;

&lt;p&gt;Both the Python and Ruby camps attempted to port it, gave up on the idea, and eventually decided that the best thing to do would be to build Lucene using a Java-&gt;native compiler, write a C wrapper around it, and then use that instead. (I'm not sure what the status is of those projects)&lt;/p&gt;&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title></includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3307882025</wfw:comment>
		</item>
		<item>
			<title>Exposing a Web Service</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3305809472</link>
			<category>examples</category>
			<pubDate>Mon, 03 Oct 2005 16:24:32 EDT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">

<p>I should do a screencast on this, but I don't have time for one today. This is the other side of the <a href="http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3304946125">client demo</a> I showed off a week or so ago. Let's say you want to expose some Smalltalk service as a web service - how does that work? Well, let's posit a class like this one, with a simple API.  These are all reduced size images; you can click through any of them for a full size image:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-1.png">
<img alt="Browser View at start" height="240" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-1-small.png" title="Browser View at start" width="300"></img></a></p>

<p>So what we have is a simple class, with a method that answers a Timestamp.  What we want to do is expose that as a service.  So, we grab the wizard from the launcher after loading the WSDL Wizard support, and select the appropriate option:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-2.png">
<img alt="Initial Wizard View" height="275" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-2-small.png" title="Initial Wizard View" width="300"></img></a></p>

<p>Then, we select the class we want to expose, and select the method(s) (via the list of protocols) that we want to make available:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-3.png">
<img alt="Select the API" height="275" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-3-small.png" title="Select the API" width="300"></img></a></p>

<p>Next, we have to define the service interface - Smalltalk is dynamically typed, but not everything in the world is - so we have to define the type information that this API will expose.  The wizard supports defining complex data types, but this example posits a simple one - Timestamp:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-4.png">
<img alt="Defining the Interface" height="228" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-4-small.png" title="Defining the Interface" width="300"></img></a></p>

<p>Next, we tell the wizard what to call the class that will support the actual server API, and what package to shove it into:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-5.png">
<img alt="Generating the Server" height="275" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-5-small.png" title="Generating the Server" width="300"></img></a></p>

<p>Next, we tell it to generate a client for us:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-6.png">
<img alt="Generating the Client" height="275" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-6-small.png" title="Generating the Client" width="300"></img></a></p>

<p>With that done, the wizard hands us some code suitable for use as a simple test case, in a workspace:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-7.png">
<img alt="Initial Wizard View" height="275" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-7-small.png" title="Initial Wizard View" width="300"></img></a></p>

<p>Last, we want it to generate some WSDL, so that other tools (or even another Smalltalk image) can talk to this service:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-8.png">
<img alt="Generating WSDL" height="275" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-8-small.png" title="Generating WSDL" width="300"></img></a></p>

<p>Once we've done all that, you should have a client and server suitable for testing - as seen below:</p>

<p><a href="http://www.cincomsmalltalk.com/blog/images/cstTools/service-9.png">
<img alt="Generated code in a Browser" height="240" src="http://www.cincomsmalltalk.com/blog/images/cstTools/service-9-small.png" title="Generated code in a Browser" width="300"></img></a></p><p>And that's pretty much it - it works the same way for more complex cases. All in all, pretty easy to work with.</p></div>]]></description>
			<guid isPermaLink="false">3305809472</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3305809472</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3305809472</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3305809472</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3305809472</includedComments:puid>
					<includedComments:author>
anonymous</includedComments:author>
					<includedComments:pubDate>2005-10-03T17:32:37-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;Comment by 
anonymous&lt;/p&gt;

&lt;p&gt;


&lt;p&gt;One suggestion: perhaps instead of generating &amp;quot;workspace&amp;quot; code to test the service, the wizard should create new TestCase subclass in form of TimeClientTest and throw appropriate method or two in there for testing... ?&lt;/p&gt;
&lt;p&gt;-Boris&lt;/p&gt;&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title>
TestCase?</includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3305809472</wfw:comment>
		</item>
		<item>
			<title>Customizing the tab widget</title>
			<link>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3303967651</link>
			<category>examples</category>
			<pubDate>Mon, 12 Sep 2005 08:47:31 EDT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">

<p>With the new tab support in <a href="http://www.cincomsmalltalk.com/BottomFeeder">BottomFeeder</a>, I thought I should explain one of the customizations - the tab menus. As it happens, the tab widget in VisualWorks doesn't support menus out of the box. So how did I add them? Well, first off, I noticed that <a href="http://wiki.cs.uiuc.edu/VisualWorks/VisualWorks+TypeLess+IRC+Client">Typeless</a> has tab menus (Typeless also ships as a BottomFeeder plugin, which is how I use it). So, I loaded TL from the <a href="http://www.cincomsmalltalk.com/CincomSmalltalkWiki/Public+Store+Repository">Public Store</a> and started having a look around. It turns out that <a href="http://www.cincomsmalltalk.com/userblogs/mls/blogView">Michael</a> extended the widget in the most natural fashion, by creating a new controller subclass. Normally, the tab bar is managed by a class called <strong>TabControlBarController. </strong>So, first thing - he created this class:</p>

<p><pre>

Smalltalk.UI defineClass: #TabControlBarControllerWithMenu
	superclass: #{UI.TabControlBarController}
	indexedType: #none
	private: false
	instanceVariableNames: 'menuHolder performer owner mouseDownIndex '
	classInstanceVariableNames: ''
	imports: ''
	category: 'UIBasics-Controllers'

</pre></p><p>Then you have to modify the view class, so that it uses this controller (or, at the time you create the view, replace it. This code just replaces the default controller) - here's TabControlBarView&gt;&gt;defaultControllerClass:</p>

<p><pre>

defaultControllerClass
	^TabControlBarControllerWithMenu

</pre></p><p>That makes sure that we always get menu support when we create a tab widget - assuming that the new controller class is implemented properly. Here's what's going on there:</p><ul xmlns="http://www.w3.org/1999/xhtml">
			<li>First, add some new instance variables to handle menus and the state required for them: menuHolder performer owner mouseDownIndex </li>
		<li>implement #yellowButtonPressedEvent: so as to know when to pop the menu</li><li>implement all the other supporting methods</li></ul><p>There's a small side story in the name of #yellowButtonPressedEvent: - back in the day, at Xerox PARC, the mouse actually had colored buttons - red, yellow, and blue. Those names still exist in the code for VW (and, I think, for Squeak). Anyway - the method:</p>

<p><pre>

yellowButtonPressedEvent: event 
	&quot;we about to bring up a menu, unlock the event
	queue so that we can process expose events.&quot;
	| index |
	view numberOfElements = 0 ifTrue: [^self]. 
	index := self findElementFor: (self sensor cursorPointFor: event).
	(self owner respondsTo: #adjustTabbarMenuFor:) ifTrue:
		[self owner adjustTabbarMenuFor: index].

	self sensor windowSensor queueLocked: false.
	self processMenuAt: event globalPoint centered: true.
	^nil

</pre></p><p>The reference to #adjustTabbarMenuFor: is something I missed out of the gate. I had to implement that in my class, in order to ensure that the menus were set up correctly - it looks like this:</p>

<p><pre>adjustTabbarMenuFor: anIndex 
	| tabModel sub tabbed menu |
	anIndex = 0 ifTrue: [^self].
	tabModel := self browserTabs at: anIndex.
	sub := self widgetAt: #feedID.
	tabbed := self getComponentFromSubcanvas: sub withID: #TwoflowerHTML1.
	menu := self class tabMenu.
	(tabbed widget tabBar component controller)
		menuHolder: (ValueHolder with: menu);
		performer: tabModel;
		owner: self.
	self checkTabMenuEnablement: menu

</pre></p><p>All of which does the following - make sure that a new tab has a menu, and that it's attached to that menu. As well, make sure that menu items are in the right enablement state. There's a few other setup methods, but you can see all of that by browsing the package <strong>RSSExtensions</strong> in the Public Store. The next important thing was setting the tabs up properly in my UI class. In my #postOpenWith: method (which fires after the UI opens, I added the following:</p>

<p><pre>

self presetTabs.
tab := self changedTab.
self setupTabMenu: tab

presetTabs
	| browserTab |
	browserTabs := OrderedCollection new.
	browserTab := RSSZoomItem new.
	browserTabs add: browserTab.
	self tabs list add: browserTab displayString.
	self tabs selectionIndex: 1.
	self setupEventHandlingForTab: browserTab

changedTab
	&quot;changed to a new tab; adjust&quot;

	| index  browserTab sub tabbed |
	index := self tabs selectionIndex max: 1.
	browserTab := self browserTabs at: index.
	sub := self widgetAt: #feedID.
	tabbed := self getComponentFromSubcanvas: sub withID: #TwoflowerHTML1.
	tabbed widget client: self htmlModel spec: #windowSpec builder: self builder.
	(browserTab feed isNil or: [browserTab feed isFake])
		ifFalse: [self focusOnItem: browserTab item].
	self tabs selectionIndex = 0
		ifTrue: [self tabs selectionIndex: 1].
	self setCurrentTabDetails.
	self setupHTMLPane.
	self setBrowserEvents.
	self restoreHistoryFrom: browserTab.
	^browserTab

setupTabMenu: aZoomItem
	| tabbed sub menu |
	sub := self widgetAt: #feedID.
	tabbed := self getComponentFromSubcanvas: sub withID: #TwoflowerHTML1.
	menu := self class tabMenu.
	(tabbed widget tabBar component controller)
		menuHolder: (ValueHolder with: menu);
		performer: aZoomItem;
		owner: self.
	self checkTabMenuEnablement: menu

</pre></p><p>Those three methods are the heart of the support. The first one sets the tabs up - with the proper domain model (in this case, an object that holds the selected feed, the selected item, and the history), and sets the current tab index. The second method, #changedTab, fires whenever a tab is selected. It ensures that the correct stuff gets displayed, and that state stays correct. The last one, #setupTabMenu: makes sure that menus are set up for selected tabs.</p><p>There's some infrastructure there - event handling, and some application specific stuff - but that's the gist of it. If you need help doing something like this, just <a href="mailto:jarober@gmail.com">send me an email</a>.</p></div>]]></description>
			<guid isPermaLink="false">3303967651</guid>
			<pingback:server>http://www.cincomsmalltalk.com/blog/servlet/CommentAPIPBServlet?guid=3303967651</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/blog/blogView?entry=3303967651</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3303967651</includedComments:guid>
					<includedComments:puid>http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;entry=3303967651</includedComments:puid>
					<includedComments:author>
Michael Lucas-Smith</includedComments:author>
					<includedComments:pubDate>2005-09-12T09:08:59-05:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;Comment by 
Michael Lucas-Smith&lt;/p&gt;

&lt;p&gt;


&lt;p&gt;Typeless tabs also do drag-n-drop reordering Jim.&lt;/p&gt;
&lt;/p&gt;
&lt;/div&gt;</includedComments:content>
					<includedComments:title>
Typeless tabs</includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/blog/blogView/servlet/CommentAPIServlet?guid=3303967651</wfw:comment>
		</item>
	</channel>
</rss>
