Scala Self-Types and the Promises You Keep

If you’ve been writing Scala code for any length of time you’ve inevitably come across the following syntax:

class UserService() {

  this: OAuthProvider =>

  def setAccessToken(user: User, authToken: String) {
    val accessToken = requestAccessToken(authToken)
    user.accessToken = accessToken
  }
}

Ok, immediately you might say “what’s going on with ‘this'”?

  this: OAuthProvider =>

That’s what we call a “self-type” declaration in Scala… but what does it do? The hint lies in the setAccessToken function and its use of some mysterious function. Is it me, or is requestAccessToken not defined anywhere? And no, I didn’t neglect to show you an import that brought that function in. Instead, the requestAccessToken function is actually defined on the OAuthProvider trait, like so:

trait OAuthProvider {
  def requestAccessToken(authToken: String)
}

“Ok”, you may say, “it’s not like we are instantiating an instance of a class that extends OAuthProvider anywhere in our code right?”. That’s true, and that’s why this self-type syntax seems so foreign to the uninitiated.

By adding this: OAuthProvider => at the top of our class, Scala accepts a promise from us, so to speak. A promise to, at instantiation time, provide a class or trait that implements the OAuthProvider trait for us. What does that remind you of? To me, it reminds me of “Dependency Injection” and that’s why it is the core concept behind the Cake Pattern.

Instead of relying on a dependency injection framework such as Spring or Guice to “wire” our dependencies, we instead rely on Scala’s ability to infer when our class has all its self-types satisfied.

Being explicit about your self-type

I’m actually not a huge fan of declaring self-types using the this: syntax. Instead I like using an alias other than this

Here’s an example similar to the one above from my product Crowdscriber:

class LinkUserService() {

  oauthProvider: OAuthProvider =>

  def setLinkAuthToken(userId: String, service: String, token: String): String = {
    //not doing anything with the service param yet
    oauthProvider.createAndStoreCredential(userId, token)
  }
}

Notice how I didn’t use the default name this for my variable? I instead called it oauthProvider and then used that alias inside the setLinkAuthToken as if it were a field injected into my class, akin to the classic way you might utilize a field injected by Spring or Guice.

Scala will complain at compile-time if I don’t mixin an implementor of OAuthProvider when I want to use my LinkUserService, so I need to either declare a new class like so:

case class GoogleLinkUserService() extends LinkUserService with GoogleOAuthProvider

or, mixin the implementing trait at declaration time:

val googleLinkService = new LinkService() with GoogleOAuthProvider

The difference between what Scala gives us with it’s self-type versus what is provided by frameworks such as Spring or Guice is that the former gives you a guaranty your dependent implementation was “wired” correctly at compile-time where as the latter can only verify correct dependency wiring at run-time. Said differently, using the self-type technique gives you “red squiggles” in your IDE when you don’t satisfy your dependencies, instead of a bunch of run-time log messages.

I hope this clears things up!

Author: craig

Share This Post On

Submit a Comment

Your email address will not be published. Required fields are marked *