2

A KorGE Game Library example game (CounterStrike) has the following construct:

sealed class SideEffect{
    class Hit() : SideEffect()
    class TerroristShot(val terrorist: Terrorist) : SideEffect()
    class KillTerrorist(val terrorist: Terrorist) : SideEffect()
    class ShowTerrorist(val terrorist: Terrorist) : SideEffect()
    class HideTerrorist(val terrorist: Terrorist) : SideEffect()
    class CounterTerroristWin : SideEffect()
    class TerroristsWin : SideEffect()   
}

and I am struggling to understand what the resulting (overall) Object actually is. Does resulting Object actually take up the space of SEVEN SideEffect classes, or ONE? (Or is this a trick question if the classes would all be identical except the name)?

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • SideEffect is implicitly abstract because it is sealed. It has seven subclasses. You will only ever have an instance of one of the seven. Defining a class inside another class doesn't make that outer class bigger. It only changes the semantics of how you reference the classes defined within it. (But you can also use the `inner` keyword on the classes defined inside the outer class, and that makes each instance of those inner classes dependent on a specific instance of the outer class.) – Tenfour04 Aug 26 '20 at 14:55

2 Answers2

2

No it just has one possibility.

This concept is more commonly known as an algebraic data type and is used to define a finite set of possibilities that a class can have.

In this case a side effect can therefore have one of the classes that are embedded in the sealed class.

The main advantage of this is that we can do something like this:

fun determineSideEffect(effect: SideEffect) = when(effect){
    is Hit -> do something when hit
    is TerroristShot -> do something when terrorist is shot
    is KillTerrorist -> do something when terrorist is killed
    is ShowTerrorist -> do something when terrorist is shown
    is HideTerrorist -> do something when terrorist is hidden
    is CounterTerroristWin -> do something when counter terrorist wins
    is TerroristsWin ->  do something when a terrorist wins
}

Notice that we don't have an else clause. Normally in a when condition we would need this, however since this is an algebraic data type and the types are known we don't need to specify it.

Daniel Jacob
  • 1,455
  • 9
  • 17
  • Yes, I was rather thinking this construction was so useful that it was somehow standard, or being used often in games, but in the about 22 example programs (many not games) in the KorGE Samples-Master set there are no additional occurrences. (Some sealed classes, but not used like this.). I have to think that this was therefore the brainchild of the author(s) of the KorGE-jam-master specific to the CounterStrike Game. – user1619183 Aug 26 '20 at 20:09
1

One way to think about it is as if you don't use sealed at all. You'll have an abstract class SideEffect, a class Hit, a class TerroristShot etc. (because sealed implies abstract).

The only difference with sealed is that the direct subclasses you've listed (Hit, etc.) are the only direct subclasses that SideEffect can ever have. You cannot add more direct subclasses anywhere else in the code.

Therefor you know that any value of type SideEffect must be an instance of one of those 7 subclasses. The SideEffect class itself is abstract, so it can never be instantiated directly.

In terms of to storage sealed class is no different from abstract class and its subclasses are no different than regular classes.

fluidsonic
  • 4,655
  • 2
  • 24
  • 34
  • Only a note: Without the sealed modifier there is an error message at each (inner) class that: "The Type is final, so it cannot be inherited from". – user1619183 Aug 26 '20 at 19:37
  • Yes, in that case you need an `abstract class` because `sealed` implies `abstract`. I've mentioned that in the last paragraph but I'll make it clear in the first too :) – fluidsonic Aug 26 '20 at 19:43