Skip to content

Inheritance example

This example shows how inheritance works in Sen.

Interface

There's a base class defined in animal.stl from which we have two subclasses in cat.stl and dog.stl.

classDiagram
    class Animal {
        Taxonomy taxonomy
        Vec2 position
        advance(a, b) [function]
        madeSound(content) [event]
    }
    class Dog {
        goodDog() [function]
        badDog() [function]
    }
    class Cat {
        jumpToLocation(x, y) [function]
    }
    Animal <|-- Dog
    Animal <|-- Cat
package animals;

// See https://en.wikipedia.org/wiki/Taxonomy_(biology)
struct Taxonomy
{
  domain  : string,
  kingdom : string,
  phylum  : string,
  type    : string,
  order   : string,
  family  : string,
  genus   : string,
  species : string,
}

quantity<u32, m> MetersU32;

// A position in a 2D-grid
struct Vec2
{
  x : MetersU32,  // Horizontal dimension
  y : MetersU32,  // Vertical dimension
}

// Base class for animals
class Animal
{
  // The taxonomy of the animal
  var taxonomy : Taxonomy [static_no_config];

  // The animal position
  var position : Vec2;

  // Advances a steps in the x direction and b steps in the y direction.
  //
  // @param a meters to advance in the x direction.
  // @param b meters to advance in the y direction.
  fn advance(a: MetersU32, b: MetersU32);

  // Emitted when the animal makes a sound.
  //
  // @param content the sound
  event madeSound(content: string);
}
import "animal.stl"

package animals;

// A Cat is an animal that can jump.
class Cat : extends Animal
{
  // Makes the cat jump to a given location.
  fn jumpToLocation(x: MetersU32, y: MetersU32);
}
import "animal.stl"

package animals;

// A Dog is an animal that can bark.
class Dog : extends Animal
{
  // Tells the dog that it's a good dog.
  fn goodDog();

  // Tells the dog that it's a bad dog.
  fn badDog();
}

Implementation

We provide an implementation of Animal, and reference it in the implementations of Cat and Dog using template parameters. With this mechanism, you can "inject" implementations in intermediate classes of a class hierarchy.

// === animal.h ========================================================================================================
//                                               Sen Infrastructure
//                   Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
//                                    See the LICENSE.txt file for more information.
//                   © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
// =====================================================================================================================

#ifndef SEN_EXAMPLES_PACKAGES_ANIMALS_SRC_ANIMAL_H
#define SEN_EXAMPLES_PACKAGES_ANIMALS_SRC_ANIMAL_H

// sen
#include "sen/core/base/compiler_macros.h"

// generated code
#include "stl/animal.stl.h"

namespace animals
{

class AnimalImpl: public AnimalBase
{
public:
  SEN_NOCOPY_NOMOVE(AnimalImpl)

public:
  using AnimalBase::AnimalBase;
  ~AnimalImpl() override = default;

protected:
  void advanceImpl(MetersU32 a, MetersU32 b) override
  {
    const auto& currentPosition = getPosition();
    setNextPosition(Vec2 {currentPosition.x + a, currentPosition.y + b});
  }
};

}  // namespace animals

#endif  // SEN_EXAMPLES_PACKAGES_ANIMALS_SRC_ANIMAL_H
// === cat_impl.cpp ====================================================================================================
//                                               Sen Infrastructure
//                   Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
//                                    See the LICENSE.txt file for more information.
//                   © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
// =====================================================================================================================

// generated code
#include "stl/cat.stl.h"

// package
#include "animal.h"

// sen
#include "sen/core/base/compiler_macros.h"
#include "sen/core/meta/class_type.h"
#include "sen/core/meta/var.h"

// generated code
#include "stl/animal.stl.h"

// std
#include <cstddef>
#include <string>

namespace animals
{

class CatImpl: public CatBase<AnimalImpl>
{
public:
  SEN_NOCOPY_NOMOVE(CatImpl)

public:
  CatImpl(const std::string name, const sen::VarMap& params): CatBase<AnimalImpl>(name, params) { init(); }

  ~CatImpl() override = default;

protected:
  void jumpToLocationImpl(MetersU32 x, MetersU32 y) override
  {
    jumpCount_++;
    setNextPosition({x, y});

    if (jumpCount_ % 3 == 0)
    {
      madeSound("meow!");
    }
  }

private:
  void init()
  {
    Taxonomy taxonomy;
    taxonomy.domain = "Eukaryota";
    taxonomy.kingdom = "Animalia";
    taxonomy.phylum = "Chordata";
    taxonomy.type = "Mammalia";
    taxonomy.order = "Carnivora";
    taxonomy.family = "Felidae";
    taxonomy.genus = "Felis";
    taxonomy.species = "F. catus";

    setNextTaxonomy(taxonomy);
  }

private:
  std::size_t jumpCount_ = 0U;
};

SEN_EXPORT_CLASS(CatImpl)

}  // namespace animals
// === dog_impl.cpp ====================================================================================================
//                                               Sen Infrastructure
//                   Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
//                                    See the LICENSE.txt file for more information.
//                   © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
// =====================================================================================================================

// generated code
#include "stl/dog.stl.h"

// package
#include "animal.h"

// sen
#include "sen/core/base/compiler_macros.h"
#include "sen/core/meta/class_type.h"
#include "sen/core/meta/var.h"

// generated code
#include "stl/animal.stl.h"

// std
#include <string>

namespace animals
{

class DogImpl: public DogBase<AnimalImpl>
{
public:
  SEN_NOCOPY_NOMOVE(DogImpl)

public:
  DogImpl(const std::string& name, const sen::VarMap& params): DogBase<AnimalImpl>(name, params) { init(); }

  ~DogImpl() override = default;

protected:
  void goodDogImpl() override { madeSound("wuff!"); }

  void badDogImpl() override { madeSound("grrr!"); }

private:
  void init()
  {
    Taxonomy taxonomy;
    taxonomy.domain = "Eukaryota";
    taxonomy.kingdom = "Animalia";
    taxonomy.phylum = "Chordata";
    taxonomy.type = "Mammalia";
    taxonomy.order = "Carnivora";
    taxonomy.family = "Canidae";
    taxonomy.genus = "Canis";
    taxonomy.species = "C. familiaris";

    setNextTaxonomy(taxonomy);
  }
};

SEN_EXPORT_CLASS(DogImpl)

}  // namespace animals

How to run it

Let's define what we want to run in our Sen kernel.

Configuration file
# $schema: ../base/schema.json
include:
  - ../base/shell.yaml

build:
  - name: myComponent
    freqHz: 30
    imports: [animals]
    group: 3
    objects:
      - class: animals.CatImpl
        name: rufus
        bus: my.tutorial
      - class: animals.DogImpl
        name: elon
        bus: my.tutorial

To run it, let's call sen run:

sen run config/2_inheritance/1_inheritance.yaml

This will open a shell and tell Sen to instantiate the cat and dog implementations in the my.tutorial bus.

You can interact with the objects by doing commands such as:

info my.tutorial.elon.print
info my.tutorial.rufus.print

info my.tutorial.elon.advance 2, 2
info my.tutorial.elon.getPosition
info my.tutorial.elon.goodDog

info my.tutorial.rufus.advance 2, 2
info my.tutorial.rufus.getPosition
info my.tutorial.rufus.jumpToPosition 4, 4
info my.tutorial.rufus.getPosition

Running it over the network

We can run it over the network using the eth component. This is the same as the first example, but you will need to start two processes.

First run:

sen run config/2_inheritance/2_inheritance_eth.yaml

Then, in another terminal or command prompt, run:

sen shell

In this new Sen instance, open the bus where we should find our objects:

open my.tutorial

You should be able to work with the objects as if you were on the same process.

Using the explorer

You can also run it using the explorer to see and interact with the objects in a more graphical way.

sen run config/2_inheritance/2_inheritance_exp.yaml

You can monitor the events produced by the instances by opening the relevant window, checking the relevant events, and looking at the event explorer window. For example, if you monitor the dog, you should be able to see events when calling the goodDog and badDog function. Same when calling the jumpToLocation on the cat.