Smalltalk-style yourself possible in Scala?

333 views
Skip to first unread message

Saxo

unread,
Dec 22, 2012, 2:10:58 PM12/22/12
to scala...@googlegroups.com
Hello,

in Smalltalk there is the nice yourself trick:

    | val coll |

    val := OrderedCollection new add: 'abc'; add: 'def'.
    Transcript cr; show: val printString. "prints 'def'"

    coll := OrderedCollection new add: 'abc'; add: 'def'; yourself.
    Transcript cr; show: coll printString. "prints an 'OrderedCollection('abc' 'def')' "

The trick is simply that yourself is a method in class Object that does nothing but returning self (which is the this pointer in Smalltalk). The whole thing is easy to do as Smalltalk is dynamically typed.

Question is whether this can also be done in Scala. I know, you can live very well without this little feature. And you can't derive much insight about Scala from whether this can be done in Scala or not. It's just a question out of curiosity. I could sit down and figure out myself, but I'm very new to Scala and this would take quite a while. Am too busy with xmas preparations at the moment ;-).

Thanks, Oliver

Sonnenschein

unread,
Dec 23, 2012, 4:45:36 AM12/23/12
to scala...@googlegroups.com
Hi Oliver,
either the answer is very simple or I didn't understand your question due to the lack of Smalltalk background:
You may return this which is a keyword. You may also declare the return type as this.type.
Peter

Saxo

unread,
Dec 23, 2012, 6:34:47 AM12/23/12
to scala...@googlegroups.com
Yourself needs to be declared to return the type of the receiver object. In my example the return type first has to be a String and in the second case has to be an OrderedCollection. But you cannot have the yourself method return a String or an OrderedCollection at the same time. Objective-C that is contrary to Smalltalk statically typed and modeled after Smalltalk has a special construct to allow for this in its type system. I just wonder how flexible Scala is in this respect and whether it can be done.

-- Oliver

Rex Kerr

unread,
Dec 23, 2012, 10:13:36 AM12/23/12
to Saxo, scala-user
I also cannot tell what the behavior is.  Can you please abstract the idiosyncratic Smalltalk notation into standard mathematics notation?  That is, what is the domain and range?  And what are the side effects?  It looks to me like Smalltalk returns the argument of the last method call instead of Unit!  This is...really weird.  Why would I want that argument in particular?

The "yourself" command seems only to rescue you from this otherwise bizarre behavior.  If you don't have the bizarre behavior to begin with, there's no "nice trick" needed.  If you're asking how to get the _non_ "yourself" case...I'm not sure there's a good way to accomplish that in Scala.

  --Rex

Sebastian Nozzi

unread,
Dec 23, 2012, 8:19:36 PM12/23/12
to scala...@googlegroups.com, Saxo
Hello,

I come from the opposite background: have some experience in Smalltalk and recently got interested in Scala. So, I hope I can shed some light into this.

Many things seem indeed strange looking at them from the Scala (or FP) point of view. The emphasis in Smalltalk is "message passing" (like "sending a message to an object"). One interesting concept is that of cascading, that I somehow miss in Scala and maybe the original poster also. It is for cascading that:

1) returning "self" (or "this") as the default value makes sense
2) "yourself" is crucial to break out from this

What is cascading?

It's the ability to send more than one message to the same receiver. In Scala/Java jargon: it's the ability to invoke different methods to the same object in one statement.

Imagine a logo turtle. In Smalltalk it looks like this:

turtle
  clear;
  forward: 10;
  turn: 90;
  forward: 20.

Note that Smalltalk statements en with a dot "."... the semicolon ";" serves for separating cascading messages (or "method invocations to a same receiver"). This could have been written like:

turtle clear.
turtle forward: 10.
turtle turn: 90.
turtle forward: 20.

Now, a common "trick" in Smalltalk is to send messages to freshly created objects to initialize them *in one step*. Thanks to cascading, instead of this:

names := OrdereCollection new.
names add: 'Peter'.
names add: 'John'.
names add: 'Paul'.

You can do this:

myInstance := (OrderedCollection new)
    add: 'Peter';
    add: 'John';
    add: 'Paul';
    ...

The "add:" messages are being sent to the result of "OrderedCollection new", which is a new instance of "OrderedCollection" (since the message "new" was sent to "OrderedCollection", which is the class for Lists).

In order for the whole expression to evaluate to the List being populated and correctly assigned to "myInstance", the last message sent to this collection needs to be "yourself":

myInstance := (OrderedCollection new)
    add: 'Peter';
    add: 'John';
    add: 'Paul';
    yourself.

Now, to the other question, the reasons why the default value of methods is "self" (or "this") is that by returning "self", you get method chaining for free (method chaining not to be confused with cascading as I presented before). This is also used in Smalltalk code, though I would be careful... Imagine:

myDbConnection close disconnect ifDisconnected: [...].

I called 3 methods after another, which would be implemented as auto-returning "self". The [...] at the end indicates a block-closure (annonymous function).

I hope this clears up a little.

Best regards,

Sebastian

Saxo

unread,
Dec 24, 2012, 5:45:56 AM12/24/12
to scala...@googlegroups.com
Very good explanation, Sebastian. Thank you. As I mentioned Objective-C has exactly the same concept as it is also based on message passing like Smalltalk, e.g. there is a so-called runtime engine that carries out message dispatch for every method at runtime. In contrast, in Java, C++ and I guess also Scala for a non-virtual method the address where to jump to invoke the function is not determined dynamically at runtime.

@Sebastian: Can you set an alias from this to self in Scala ;-)) ? Smalltalkers understand ...

-- Oliver

Flávio W. Brasil

unread,
Dec 24, 2012, 6:45:51 AM12/24/12
to Saxo, scala...@googlegroups.com
Hello Saxo.

I am a Smalltalker too! :)

It is possible to have cascade and yourself using implicits:


turtle.cascade(
_.clear,
_.forward(10),
_.turn(90),
_.forward(20),
_.yourself)


But, since this construct is valuable only if you work with mutable state, I avoid it at maximun.

-- 
Flávio W. Brasil
{persistence as it should be}

Rex Kerr

unread,
Dec 24, 2012, 7:12:08 AM12/24/12
to Sebastian Nozzi, scala-user, Saxo
On Sun, Dec 23, 2012 at 8:19 PM, Sebastian Nozzi <sebn...@gmail.com> wrote:

In order for the whole expression to evaluate to the List being populated and correctly assigned to "myInstance", the last message sent to this collection needs to be "yourself":

myInstance := (OrderedCollection new)
    add: 'Peter';
    add: 'John';
    add: 'Paul';
    yourself.

Okay, but this leaves the most baffling question unanswered: why does it return 'Paul' if you omit yourself?

This seems like either an implementation detail of the Smalltalk VM leaking through (in that e.g. 'Paul' is already on the stack, so why not just leave it there), or enabling of something like
  a += b += c += 'Paul'
where the intention is to add 'Paul' to all three lists.  Why that would be the favored use-case, I have no idea.
 

Now, to the other question, the reasons why the default value of methods is "self" (or "this") is that by returning "self", you get method chaining for free

Sure, but that's not what you get by default; if you got it by default then you wouldn't need to use "yourself".

Anyway, you can do any of these things in Scala, possibly with a little extra tooling.

"Cascading" with new (actually just a custom constructor):

  val myInstance = new OrderedCollection {
    add "Peter"
    add "John"
    add "Paul"
  }

Chaining without new:
  // assuming def add(s: String): OrderedCollection, which is sensible
  myInstance.tail.add("Mary").add("Joseph")

Cascading with non-self returns:
  implicit class TapAnything[A](val tapped: A) extends AnyVal {
    def tap[B](f: A => B): A = { f(tapped); tapped }
    def taps(f: A => Unit, g: A => Unit, hs: (A => Unit)*): A = {
      f(tapped); g(tapped); hs.foreach(_(tapped)); tapped
    }
  }

  List("fish").taps(println, x => println(x.length))

But I still get the impression that I'm missing some essence of what is desired as inspired by Smalltalk.

  --Rex

P.S. class X { self =>  /* now self == this */ }

Daniel Sobral

unread,
Dec 24, 2012, 7:36:08 AM12/24/12
to Sebastian Nozzi, scala-user, Saxo
This comes up from time to time. One suggestion to deal with it is importing the methods into scope:

val x = new java.lang.ListArray[String]
locally {
  import x._
  add("Peter")
  add("John")
  add("Paul")
}

But this merely seeks to reproduce this *coding style*. While it uses some Scala features, I wouldn't call it idiomatic, as I hardly ever see it done. Scala, like Java in recent years, favor fluent interfaces, particularly with build pattern, such as in the Java library example below:

Request r = new RequestBuilder().setUrl("url")
                     
.setRealm((new Realm.RealmBuilder()).setPrincipal(user)
                     
.setPassword(admin)
                     
.setRealmName("MyRealm")
                     
.setScheme(Realm.AuthScheme.DIGEST).build());
r
.execute();
Java libraries will usually work with mutable instances that get changed by the builder. Scala libraries, on the other hand, often offer immutable instances whose methods return new instances with further modifications. That's what collection manipulation usually looks like.

--
Daniel C. Sobral

I travel to the future all the time.

Sebastian Nozzi

unread,
Dec 27, 2012, 5:02:13 AM12/27/12
to scala...@googlegroups.com, Sebastian Nozzi, Saxo
Hello Rex,

I am not an expert myself, so I posted these two questions both in Smalltalk mailing lists and Stackoverflow.



Since this is a Scala mailing list, and not Smalltalk, I will refrain from giving further explanations here ;-)

As a Smalltalk enthusiast, I really like the "cascading" feature. But I agree completely that not every language feature can be "translated" from one to the other. I also see that in this case it would be not be "idiomatic" Scala, and also that from Scala's philosophy and point of view the emphasis is on immutability.

I guess missing features is normal when moving from one language to the other, until one acquires the corresponding "mindset".

Best regards,

Sebastian

P.S. By the way, I encourage everyone interested in learning good object-oriented design to take a look at Smalltalk. It could improve your design skills even if you end up not using the language for production work (the same thing Eric Raymond said about Lisp ;-).



El lunes, 24 de diciembre de 2012 13:12:08 UTC+1, Rex Kerr escribió:
Okay, but this leaves the most baffling question unanswered: why does it return 'Paul' if you omit yourself?
... 

Sure, but that's not what you get by default; if you got it by default then you wouldn't need to use "yourself".
... 

Saxo

unread,
Dec 27, 2012, 8:25:35 AM12/27/12
to scala...@googlegroups.com
  val myInstance = new OrderedCollection {
    add "Peter"
    add "John"
    add "Paul"
  }


Thanks for this one.  Looks cool.


Okay, but this leaves the most baffling question unanswered: why does it return 'Paul' if you omit yourself?

The add method returns the added object. So you can easily  continue with the added value withou having to store it in some temporary variable.


This seems like either an implementation detail of the Smalltalk VM leaking through

Errr, what? It's entirely in the library.


Scala, like Java in recent years, favor fluent interfaces, particularly with build pattern, such as in the Java library example below:

The builder patthern in Java is a way to achieve what you get in Smalltalk and Objective-C for free. 

The syntax of Smalltalk fits almost onto 1 sheet of paper. This is not because the language is simplistic, but because the language creators thought about how to keep it simple and concise.

-- Oliver

Matthew Pocock

unread,
Dec 27, 2012, 8:33:44 AM12/27/12
to Sebastian Nozzi, scala...@googlegroups.com, Saxo
Hi,

This looks like one of those things that comes up if you use mutable data structures but goes away with immutable ones. To get the same effect for mutable classes in scala or java, you would tend to use a builder that provides a neat syntax that wraps this all up. I can't help feeling that each mutable class has an obvious least-surprise builder, which could be (type-)macro-generated.

Matthew
--
Dr Matthew Pocock
Integrative Bioinformatics Group, School of Computing Science, Newcastle University
skype: matthew.pocock
tel: (0191) 2566550

ScottC

unread,
Dec 27, 2012, 1:32:29 PM12/27/12
to scala...@googlegroups.com
The builder pattern works equally well for mutable and immutable objects. In Java it is most often applied to immutable objects. A Java typical setter pattern works for mutable objects, and the setters can return 'this'. A mutable object returning 'this' from setters is _not_ the builder pattern.
The builder pattern is useful in Scala and with immutable data structures when the data structure performance is poor when building it one piece at a time (see Vector) or for classes with many fields when named parameters and defaults are not sufficiently clear and flexible.

ScottC

unread,
Dec 27, 2012, 1:58:48 PM12/27/12
to scala...@googlegroups.com
What is interesting here is being able to change a methods return type to return the object the method is on instead of what is declared on the method, so that library designers never have to choose between returning 'self' and something else. In the presence of immutable collections returning new instances with each 'add' there is no oppirtunity to return anything other than the new instance.

With builders (when mutable) this situation occurs again, except that there is a strong bias for a chainable api with builders.

Are there other typical uses of this 'yourself' feature in smalltalk besides collections and object construction? In those two cases it does not play well with immutability or is replaced with the builder pattern.

Getting something 'builder like' for free is interesting, but setting fields one at a time after construction is not an immutable object builder pattern.

Saxo

unread,
Dec 27, 2012, 4:40:12 PM12/27/12
to scala...@googlegroups.com
Are there other typical uses of this 'yourself' feature  in smalltalk besides collections and object construction?


At least to my knowledge, there isn't. From what I can tell adding a method to class Object that simply returns self (aka this) is only a little trick that comes cheap in a language without static typing.

-- Oliver

Rex Kerr

unread,
Dec 27, 2012, 5:01:03 PM12/27/12
to Saxo, scala-user
It comes cheap in any language with extension methods, and would in Scala with value classes except for an implementation limitation.  This ought to work but does not for no good reason:

  implicit class YouAreYourself[A](val you: A) extends AnyVal { def yourself: you.type = you }

If you don't care about exact identity, but only that yourself promises the same type, then

  implicit class YouAreYourself[A](val yourself: A) extends AnyVal {}

does the it-is-cheap trick already (in 2.10).  (Some JIT optimization required for full cheapness.)

--Rex

Saxo

unread,
Dec 27, 2012, 5:21:24 PM12/27/12
to scala...@googlegroups.com
implicit class YouAreYourself[A](val you: A) extends AnyVal { def yourself: you.type = you }

This is interesting. Thanks.

It comes cheap in any language with extension methods

No, extension methods alone do not suffice. The type system, if a statically typed one, needs to be able to map the return type as required by the context. I don't know of any statically typed language that can do this except Objective-C and maybe Scala. It could not be done in Java if it had extension methods, for example: the return typoe is fixed and cannot be changed as required.


The builder pattern is useful in Scala and with immutable data structures when the data structure performance is poor when building it one piece at a time (see Vector) or for classes with many fields when named parameters and defaults are not sufficiently clear and flexible.

Let's say some mutable object only lives inside a method, stored in a temporary variable of the method. It didn't come in through a method parameter and will not leave the method. In that case I wouldn't mind changing it in a destructive way. Of course, some recursive solution would be nice where only new values are returned and thus no destructive changes take place. But the effort to find the recursicve solution has to be reasonable and performance has to be reasonable as well. That doesn't mean that I don't consider builders useful. Only a side-remark.

-- Oliver

Flávio W. Brasil

unread,
Dec 28, 2012, 6:57:54 AM12/28/12
to scala...@googlegroups.com
Did you see my example using implicits to do cascade/yourself?


turtle.cascade(
_.clear,
_.forward(10),
_.turn(90),
_.forward(20),
_.yourself)
-- 
Flávio W. Brasil
{persistence as it should be}

Chris Marshall

unread,
Dec 28, 2012, 7:16:46 AM12/28/12
to fwbr...@gmail.com, scala...@googlegroups.com
Seems a bit simpler to me

  implicit class IdW[A](a: A) {
      class Chain(f: A => Unit) { 
        def andAlso(g: A => Unit) = new Chain(a => { f(a); g(a) })
        def run = f(a) 
      }
      def chaining(f: A => Unit) = new Chain(f)
    }

Then:

scala> class X(var i: Int, var s: String, var f: Float) { override def toString = i + " " + s + " " + f }
defined class X

scala> val x = new X(0, "", 0.0F)
x: X = 0  0.0

scala> x chaining (_.i = 4) andAlso (_.s = "a") andAlso (_.f = 1.4F) run

scala> x
res7: X = 4 a 1.4



Date: Fri, 28 Dec 2012 09:57:54 -0200
From: fwbr...@gmail.com
To: scala...@googlegroups.com
Subject: Re: [scala-user] Re: Smalltalk-style yourself possible in Scala?

Flávio W. Brasil

unread,
Dec 28, 2012, 8:18:40 AM12/28/12
to Chris Marshall, scala...@googlegroups.com
It is a simpler solution, but lacks two important characteristics of the smalltalk cascading:

1. The cascade should return the result/type of the last "chain".
2. It is missing the "yourself" implementation.

-- 
Flávio W. Brasil
{persistence as it should be}

Chris Marshall

unread,
Dec 28, 2012, 9:40:17 AM12/28/12
to fwbr...@gmail.com, scala...@googlegroups.com
That's true; you'd add a return value to the run method. It has the advantage of being more functional though IMHO


Date: Fri, 28 Dec 2012 11:18:40 -0200
From: fwbr...@gmail.com
To: oxbow...@hotmail.com
CC: scala...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages