The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Of Empty Collections

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
Of Empty Collections Posted: May 29, 2008 4:54 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Of Empty Collections
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

Once upon a time, we Smalltalkers found that the binary branches associated with whether an object is nil or not, was so common, that it warranted it's own set of messages. The ifNil:/ifNotNil: variants. They're more than just shortcuts for == nil ifTrue: though, because the ifNotNil: can pass along the receiver to the block and make expressions simpler.

Yesterday, I was doing some Inspector refactoring, and found probably the next most common set of binary branch scenarios. I was dealing with lots of collections, doing lots of first and last sends, but I kept having to deal with the case where the collection was empty. This is a common problem with code that deals with collections, dealing with the empty collection scenario.

I had recently heard of a lastOrNil/firstOrNil set of extensions, and experimented with those. I needed to distinguish between nil and an empty case though. So I ended up generalizing them to:


lastOr: aBlock

   ^self isEmpty ifFalse: [self last] ifTrue: [aBlock value]

and the analagous firstOr:. These turned out to be kind of handy, for the work I was doing. I could do any of:
  1. Handle the lastOrNil with only two more characters:
    
    aSequence lastOr: nil.
    
    
  2. Use an available object:
    aSequence lastOr: [whenEmptyAnswer].
    
    
  3. Compute an object when it's empty:
    aSequence lastOr: [self askUserForValueThen].
    
    
  4. Do an out of scope return:
    ^current == aSequence lastOr: [^false].
    
    

For what I was doing, it was nice, made things terser, more expressive. But I have some issues with it. It basically boils down to wondering how this is better than adding all sorts of common composite logic types. Things like select:do:, and:ifTrue, etc. At some point, these simplified expressions lose their value, because the sheer amount of them makes finding and learning them offset the value gained. In this case, the potential for expansion, is basically what about things like any. Should there be an anyOr:? Do we need to provide a fooOr: variant for every foo which requires a non empty collection?

I've spent a little bit of time pondering how else one might solve the problem in a general fasion. Here's at least two of them, with my thoughts. Nothing really seems elegant.

One approach might be to capture the collection unit of work in a block and use exceptions to deal with it. The following code:


["do some work"] on: EmptyCollectionError do: [:ex | "deal with exceptional case"]

Could be wrapped up with sugar helpers so that you could do things like:

[aSequence last] ifEmptyDo: [nil]

There's not realy much savings here. And you get into all kinds of problems with what happens if the unit of work is more involved than a simple message send, and the error being caught is propogated from some deeper collection failure.

Another approach is to follow the ifNil:ifNotNil: pattern. Add ifEmpty:ifNotEmpty: variants to collection. If we cull the receiver into the empty block, then we gain similiar advantages as we did with ifNil:ifNotNil: E.g.


(fiveRandomTimes select: [:each | each > threashold]) ifEmpty: [0] ifNotEmpty: [:times | times last]

Maybe this is better than:

| times |

times := fiveRandomTimes select: [:each | each > threashold].

^times isEmpty ifTrue: [0] ifFalse: [times last]

Maybe not. Depends on the context I imagine. I kind of like this approach. But it doesn't make things near as terse as the original lastOr: implmentation. But it is more general. One thing that may bother me about it is the words being used. The empty pattern puts the focus on the empty state. It's longer than Nil, and when you're looking for terse, every character counts. Perhaps if there were a short simple word that meant not empty. Full comes to mind, but I think it's wrong, because it implies that a limit has been reached. I played with Wordnet for a couple of minutes. ifBare: and ifSized: came to mind. Nothing stellar in short. Another disadvantage, is that the partial cases aren't as clear. aCollection ifEmpty: [4] should return what if aCollection is not empty? One nifty trick you can play with the culled blocks and symbols, is that you can do this (message name itself aside):

aSequence ifSized: #last ifVoid: [nil]

Read: Of Empty Collections

Topic: In Space, no one can hear you flush Previous Topic   Next Topic Topic: Goodby iPhone, Welcome Back Palm Treo

Sponsored Links



Google
  Web Artima.com   

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