Domanda

Background

In Smalltalk, if you don't excplicitly return anything then the message passing evaluates to the receiver (or "self" in the message context).

For example, given this method:

MyClass >> myMethod
  Transcript show: 'hello'; cr.

Evaluating (doint "print-it") this:

| myInstance |
myInstance := MyClass new.
myInstance myMethod.

If <print-it> is done to the last invocation, then the result would be the instance itself.

Questions

  • Why was this designed this way?
  • What is the idea behind it?
  • What was the philosophical background?
  • What are the practical benefits from it? Is it to facilitate method chaining?
È stato utile?

Soluzione

One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object.

Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do.

Altri suggerimenti

Smalltalk-80's Blue Book (The Language and its Implementation) doesn't say anything regarding why it returns receiver by default.

However, there is a quote in page 27 (Section "Returning values") that might help you:

"Even if no information needs to be communicated back to the sender, a receiver always returns a value for the message expression. Returning value indicates the response to the message is complete. (...)"

Keep in mind that in Smalltalk methods are activated by means of message sends, so there is a complete round-trip for a message (that might end in a MessageNotUnderstood exception). The concept of message sending is paramount.

There are some good practice patterns on what to return depending on the intention of the message, but that's subject of other story.

I'm not a creator of a smalltalk, but it seems to be the best thing to do.

For example if you'll execute:

var := myInstance myMethod.

then the question is: what do you want var to become? One option will be nil. But it's a bit confusing, because you are working with defined objects and nil is actually an undefined one. So you can treat it as you are assigning myInstance to var and just calling myMethod along the way. Also this can be probably treated as a shorthand for

 var := myInstance myMethod; yourself.

If you'll look from the inside, then from all data available to the object itself the most appropriate thing is probably also self. Once again, the nil can be returned, but I've told my opinion on it before.

In Smalltalk there is no such thing as a void method that returns nothing, and there is no type checking. So a method just has to return something. It's like the Object says:

I can return myself for any method call by default because I always know about myself, and you can redefine this behavior in case you want me to return something else.

Personally I think that returning nil might be good too, and Objective-C applications use nil stuff very often, but Smalltalk is made this way and I think it's a quite good solution.

Methods return self by default for several reasons.

  1. Smalltalk methods must return something
  2. self is the easiest object to return
  3. self is the fastest object to return
  4. Returning self allows several design patterns to work naturally

Let me explain #4 a bit more. One common pattern for object initialization is to define a new method for the class which looks like this:

new
   ^super new initialize

This pattern depends on initialize returning self. It's not normal, however, to add a ^self at the end of an initialize method. It's unnecessary because the method will return self anyway.

In the end, returning self is just a natural choice by default given that you must return something.

Coming from Java you know of NullPointExceptions when dealing with undefined return values. Furthermore your code has to do conditional checking for null here and there.

Therefore I was happy to find a return value for every method invocation or message send in Smalltalk. If you decide to have every method return some value you are about to ask what your default value could be. The object itself (self) is a very natural way to use as default value. Or to ask the other way round: what could be a better return value?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top