What does "self" mean in Scala?


#1

I have noticed trait definitions like this

trait SomeTrait{ self =>
  def isDefinedAt(x: String): Boolean
}

What does this “self” exactly do? Any documentation about it?


#2

You can read about it here: https://docs.scala-lang.org/tour/self-types.html
When it is used without a type annotation like in your example it’s basically just defining an alias for this. A good use case is when you are working with inner classes:

class Foo { outer =>
  class Bar {
    def getFoo: Foo = outer
  }
}

#3

Jasper’s answer is spot on for the example you are asking about. It is interesting to note that while these are called self-types, They don’t have to use the name self, as Jasper’s example showed. When I saw the title of the question and not the full text, a different situation popped into my mind, so I’m going to mention that here as well. If you start using Akka, the name self is used to refer to the ActorRef of an Actor. You will see that usage far more in Scala code using Actors than you likely will see self-types in normal Scala code.


#4

That’s one use, which avoid the Foo.this you’d have to use in Java. The other use is to force a type on the class the trait is mixed in (hence the name self type, I suppose):

trait SomeTrait { self: SomeType =>
  ...
}

This makes SomeTrait usable only in classes that have type (or subtype) SomeType. You can use more complex variations, e.g., to require the using class to have two types:

trait SomeTrait { self: SomeType with SomeOtherType =>
  ...
}

#5

Does this mean that only SomeType can extend trait SomeTrait?


#6

No – it means that anything extending SomeTrait must also extend SomeType.


#7

At least any concrete type that you can instantiate must include SomeType in its hierarchy.


#8

SomeType or a subtype of SomeType. It lets you create dependencies among modules. For instance:

class System extends Base with CompA with CompB with CompC

If CompA needs to use something from CompC, it can be defined as:

trait CompA { self: CompC => ... }

In this case:

class System extends Base with CompA with CompB

cannot be compiled because System does not have type CompC.

If CompA needs to use something from CompB and CompC, it can be defined as:

trait CompA { self: CompB with CompC => ... }

If CompA needs so much that it only makes sense in this particular system, it can be written as:

trait CompA { self: Base => ... }

In this example, CompA, CompB and CompC are traits; Base can be a trait or a class.