Take a look at this:
/** takes a Spellbook and returns a Spellbook guaranteeing
* that all spells have been loaded from the database. */
def checkIfSpellsLoaded[S <: Spellbook](spellbook :S) :Option[S { type SpellsLoaded }] =
if (spellbook.spellsLoaded) Some(spellbook.asInstanceOf[S { type SpellsLoaded }])
else None
def checkIfOwnerLoaded[S <: Spellbook](spellbook :S) :Option[S { type OwnerLoaded }] =
if (spellbook.ownerLoaded) Some(spellbook.asInstanceOf[S { type OwnerLoaded }])
else None
What is that { type X } doing as part of a type parameter?? What is going on here?
In Scala class members can be
def,valand (relevant for us)typehttps://docs.scala-lang.org/tour/abstract-type-members.html
https://typelevel.org/blog/2015/07/13/type-members-parameters.html
Scala: Abstract types vs generics
How to work with abstract type members in Scala
Type members are used to create path-dependent types
What is meant by Scala's path-dependent types?
https://docs.scala-lang.org/scala3/book/types-dependent-function.html
If
Spellbookhas type membersSpellsLoaded,OwnerLoadedthen for
S <: Spellbookthe typesS,S { type SpellsLoaded }andS { type OwnerLoaded }are the sameBut if
Spellbookdoesn't have type membersSpellsLoaded,OwnerLoadedthen the refined types
S { type SpellsLoaded }andS { type OwnerLoaded }are just subtypes ofS(having those type members)and the refined types
S { type SpellsLoaded = ... }andS { type OwnerLoaded = ... }in their turn are subtypes of the former refined typesS { type SpellsLoaded }andS { type OwnerLoaded }are shorthands forS { type SpellsLoaded >: Nothing <: Any }andS { type OwnerLoaded >: Nothing <: Any }whileS { type SpellsLoaded = SL }andS { type OwnerLoaded = OL }are shorthands forS { type SpellsLoaded >: SL <: SL }andS { type OwnerLoaded >: OL <: OL }.Casting
.asInstanceOf[S { type SpellsLoaded }],.asInstanceOf[S { type OwnerLoaded }]looks likeSpellsLoaded,OwnerLoadedare used as phantom typeshttps://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:labelled-generic:type-tagging (5.2 Type tagging and phantom types)
So you seem to encode in types that the methods
checkIfSpellsLoaded,checkIfOwnerLoadedwere applied toS.See also
Confusion about type refinement syntax
What is a difference between refinement type and anonymous subclass in Scala 3?