diff --git a/src/pystencilssfg/composer/basic_composer.py b/src/pystencilssfg/composer/basic_composer.py
index c0b420f6c51a2fd228a4d96f3451aa83c8612205..936d5c5a6d5aa6988bcf1f2f615c872ef87f162c 100644
--- a/src/pystencilssfg/composer/basic_composer.py
+++ b/src/pystencilssfg/composer/basic_composer.py
@@ -111,7 +111,7 @@ class KernelsAdder:
         self._kernel_namespace.add_kernel(khandle)
 
         for header in kernel.required_headers:
-            #   TODO: Find current source file by traversing namespace blocks upward?
+            assert self._ctx.impl_file is not None
             self._ctx.impl_file.includes.append(HeaderFile.parse(header))
 
         return khandle
@@ -217,7 +217,7 @@ class SfgBasicComposer(SfgIComposer):
         generator.generate(SfgComposer(self))
 
     @property
-    def kernels(self) -> SfgKernelNamespace:
+    def kernels(self) -> KernelsAdder:
         """The default kernel namespace.
 
         Add kernels like::
@@ -227,12 +227,20 @@ class SfgBasicComposer(SfgIComposer):
         """
         return self.kernel_namespace("kernels")
 
-    def kernel_namespace(self, name: str) -> SfgKernelNamespace:
+    def kernel_namespace(self, name: str) -> KernelsAdder:
         """Return the kernel namespace of the given name, creating it if it does not exist yet."""
-        #   TODO: Find the default kernel namespace as a child entity of the current
-        #   namespace, or create it if it does not exist
-        #   Then create a new namespace block, place it at the cursor position, and expose
-        #   it to the user via an adder
+        kns = self._cursor.get_entity("kernels")
+        if kns is None:
+            kns = SfgKernelNamespace("kernels", self._cursor.current_namespace)
+            self._cursor.add_entity(kns)
+        elif not isinstance(kns, SfgKernelNamespace):
+            raise ValueError(
+                f"The existing entity {kns.fqname} is not a kernel namespace"
+            )
+
+        kns_block = SfgNamespaceBlock(kns)
+        self._cursor.write_impl(kns_block)
+        return KernelsAdder(self._ctx, kns_block)
 
     def include(self, header_file: str | HeaderFile, private: bool = False):
         """Include a header file.
@@ -258,7 +266,9 @@ class SfgBasicComposer(SfgIComposer):
 
         if private:
             if self._ctx.impl_file is None:
-                raise ValueError("Cannot emit a private include since no implementation file is being generated")
+                raise ValueError(
+                    "Cannot emit a private include since no implementation file is being generated"
+                )
             self._ctx.impl_file.includes.append(header_file)
         else:
             self._ctx.header_file.includes.append(header_file)
@@ -271,32 +281,23 @@ class SfgBasicComposer(SfgIComposer):
         Returns:
             The created class object
         """
-        cls = self._struct_from_numpy_dtype(name, dtype, add_constructor=add_constructor)
-        self._ctx.add_entity(cls)
+        cls = self._struct_from_numpy_dtype(
+            name, dtype, add_constructor=add_constructor
+        )
+        self._cursor.add_entity(cls)
         self._cursor.write_header(SfgEntityDecl(cls))
         return cls
 
-    def kernel_function(
-        self, name: str, ast_or_kernel_handle: Kernel | SfgKernelHandle
-    ):
+    def kernel_function(self, name: str, kernel: Kernel | SfgKernelHandle):
         """Create a function comprising just a single kernel call.
 
         Args:
             ast_or_kernel_handle: Either a pystencils AST, or a kernel handle for an already registered AST.
         """
-        if self._ctx.get_function(name) is not None:
-            raise ValueError(f"Function {name} already exists.")
-
-        if isinstance(ast_or_kernel_handle, Kernel):
-            khandle = self._ctx.default_kernel_namespace.add(ast_or_kernel_handle)
-            tree = SfgKernelCallNode(khandle)
-        elif isinstance(ast_or_kernel_handle, SfgKernelHandle):
-            tree = SfgKernelCallNode(ast_or_kernel_handle)
-        else:
-            raise TypeError("Invalid type of argument `ast_or_kernel_handle`!")
+        if isinstance(kernel, Kernel):
+            kernel = self.kernels.add(kernel, name)
 
-        func = SfgFunction(name, tree)
-        self._ctx.add_function(func)
+        self.function(name)(self.call(kernel))
 
     def function(
         self,
@@ -329,10 +330,14 @@ class SfgBasicComposer(SfgIComposer):
         def sequencer(*args: SequencerArg):
             tree = make_sequence(*args)
             func = SfgFunction(
-                name, self._cursor.current_namespace, tree, return_type=create_type(returns), inline=inline
+                name,
+                self._cursor.current_namespace,
+                tree,
+                return_type=create_type(returns),
+                inline=inline,
             )
-            self._ctx.add_entity(func)
-            
+            self._cursor.add_entity(func)
+
             if inline:
                 self._cursor.write_header(SfgEntityDef(func))
             else:
@@ -530,11 +535,15 @@ class SfgBasicComposer(SfgIComposer):
             (asvar(c) if isinstance(c, _VarLike) else c) for c in lhs_components
         ]
         return SfgDeferredVectorMapping(components, rhs)
-    
+
     def _struct_from_numpy_dtype(
         self, struct_name: str, dtype: np.dtype, add_constructor: bool = True
     ):
-        cls = SfgClass(struct_name, self._cursor.current_namespace, class_keyword=SfgClassKeyword.STRUCT)
+        cls = SfgClass(
+            struct_name,
+            self._cursor.current_namespace,
+            class_keyword=SfgClassKeyword.STRUCT,
+        )
 
         fields = dtype.fields
         if fields is None:
@@ -556,12 +565,13 @@ class SfgBasicComposer(SfgIComposer):
             constr_inits.append(f"{member}({arg})")
 
         if add_constructor:
-            cls.default.append_member(SfgEntityDef(SfgConstructor(constr_params, constr_inits)))
+            cls.default.append_member(
+                SfgEntityDef(SfgConstructor(constr_params, constr_inits))
+            )
 
         return cls
 
 
-
 def make_statements(arg: ExprLike) -> SfgStatements:
     return SfgStatements(str(arg), (), depends(arg), includes(arg))
 
diff --git a/src/pystencilssfg/composer/class_composer.py b/src/pystencilssfg/composer/class_composer.py
index 489823b9ce619be88e3220ce4b941cf49c62b298..1e3e6a3085b3bc1a716930ccbc8d74381b33e05d 100644
--- a/src/pystencilssfg/composer/class_composer.py
+++ b/src/pystencilssfg/composer/class_composer.py
@@ -1,26 +1,28 @@
 from __future__ import annotations
 from typing import Sequence
+from itertools import takewhile, dropwhile
 
 from pystencils.types import PsCustomType, UserTypeSpec, create_type
 
+from ..context import SfgContext
 from ..lang import (
-    _VarLike,
     VarLike,
     ExprLike,
     asvar,
     SfgVar,
 )
 
+from ..ir.call_tree import SfgCallTreeNode
 from ..ir.source_components import (
     SfgClass,
-    SfgClassMember,
-    SfgInClassDefinition,
     SfgConstructor,
     SfgMethod,
     SfgMemberVariable,
     SfgClassKeyword,
     SfgVisibility,
     SfgVisibilityBlock,
+    SfgEntityDecl,
+    SfgEntityDef,
 )
 from ..exceptions import SfgException
 
@@ -40,31 +42,87 @@ class SfgClassComposer(SfgComposerMixIn):
     Its interface is exposed by :class:`SfgComposer`.
     """
 
-    class VisibilityContext:
+    class VisibilityBlockSequencer:
         """Represent a visibility block in the composer syntax.
 
         Returned by `private`, `public`, and `protected`.
         """
 
         def __init__(self, visibility: SfgVisibility):
-            self._vis_block = SfgVisibilityBlock(visibility)
-
-        def members(self):
-            yield from self._vis_block.members()
+            self._visibility = visibility
+            self._args: tuple[
+                SfgClassComposer.MethodSequencer
+                | SfgClassComposer.ConstructorBuilder
+                | VarLike
+                | str,
+                ...,
+            ]
 
         def __call__(
             self,
             *args: (
-                SfgClassMember | SfgClassComposer.ConstructorBuilder | VarLike | str
+                SfgClassComposer.MethodSequencer
+                | SfgClassComposer.ConstructorBuilder
+                | VarLike
+                | str
             ),
         ):
-            for arg in args:
-                self._vis_block.append_member(SfgClassComposer._resolve_member(arg))
+            self._args = args
+            return self
 
+        def _resolve(self, ctx: SfgContext, cls: SfgClass):
+            vis_block = SfgVisibilityBlock(self._visibility)
+            for arg in self._args:
+                match arg:
+                    case (
+                        SfgClassComposer.MethodSequencer()
+                        | SfgClassComposer.ConstructorBuilder()
+                    ):
+                        arg._resolve(ctx, cls, vis_block)
+                    case str():
+                        vis_block.elements.append(arg)
+                    case _:
+                        var = asvar(arg)
+                        member_var = SfgMemberVariable(var.name, var.dtype, cls)
+                        cls.add_member(member_var, vis_block.visibility)
+                        vis_block.elements.append(member_var)
+
+    class MethodSequencer:
+        def __init__(
+            self,
+            name: str,
+            returns: UserTypeSpec = PsCustomType("void"),
+            inline: bool = False,
+            const: bool = False,
+        ) -> None:
+            self._name = name
+            self._returns = create_type(returns)
+            self._inline = inline
+            self._const = const
+            self._tree: SfgCallTreeNode
+
+        def __call__(self, *args: SequencerArg):
+            self._tree = make_sequence(*args)
             return self
 
-        def resolve(self, cls: SfgClass) -> None:
-            cls.append_visibility_block(self._vis_block)
+        def _resolve(
+            self, ctx: SfgContext, cls: SfgClass, vis_block: SfgVisibilityBlock
+        ):
+            method = SfgMethod(
+                self._name,
+                cls,
+                self._tree,
+                return_type=self._returns,
+                inline=self._inline,
+                const=self._const,
+            )
+            cls.add_member(method, vis_block.visibility)
+
+            if self._inline:
+                vis_block.elements.append(SfgEntityDef(method))
+            else:
+                vis_block.elements.append(SfgEntityDecl(method))
+                ctx._cursor.write_impl(SfgEntityDef(method))
 
     class ConstructorBuilder:
         """Composer syntax for constructor building.
@@ -107,13 +165,19 @@ class SfgClassComposer(SfgComposerMixIn):
             self._body = body
             return self
 
-        def resolve(self) -> SfgConstructor:
-            return SfgConstructor(
+        def _resolve(
+            self, ctx: SfgContext, cls: SfgClass, vis_block: SfgVisibilityBlock
+        ):
+            ctor = SfgConstructor(
+                cls,
                 parameters=self._params,
                 initializers=self._initializers,
                 body=self._body if self._body is not None else "",
             )
 
+            cls.add_member(ctor, vis_block.visibility)
+            vis_block.elements.append(SfgEntityDef(ctor))
+
     def klass(self, class_name: str, bases: Sequence[str] = ()):
         """Create a class and add it to the underlying context.
 
@@ -133,19 +197,19 @@ class SfgClassComposer(SfgComposerMixIn):
         return self._class(class_name, SfgClassKeyword.STRUCT, bases)
 
     @property
-    def public(self) -> SfgClassComposer.VisibilityContext:
+    def public(self) -> SfgClassComposer.VisibilityBlockSequencer:
         """Create a `public` visibility block in a class body"""
-        return SfgClassComposer.VisibilityContext(SfgVisibility.PUBLIC)
+        return SfgClassComposer.VisibilityBlockSequencer(SfgVisibility.PUBLIC)
 
     @property
-    def protected(self) -> SfgClassComposer.VisibilityContext:
+    def protected(self) -> SfgClassComposer.VisibilityBlockSequencer:
         """Create a `protected` visibility block in a class or struct body"""
-        return SfgClassComposer.VisibilityContext(SfgVisibility.PROTECTED)
+        return SfgClassComposer.VisibilityBlockSequencer(SfgVisibility.PROTECTED)
 
     @property
-    def private(self) -> SfgClassComposer.VisibilityContext:
+    def private(self) -> SfgClassComposer.VisibilityBlockSequencer:
         """Create a `private` visibility block in a class or struct body"""
-        return SfgClassComposer.VisibilityContext(SfgVisibility.PRIVATE)
+        return SfgClassComposer.VisibilityBlockSequencer(SfgVisibility.PRIVATE)
 
     def constructor(self, *params: VarLike):
         """In a class or struct body or visibility block, add a constructor.
@@ -172,76 +236,55 @@ class SfgClassComposer(SfgComposerMixIn):
             const: Whether or not the method is const-qualified.
         """
 
-        def sequencer(*args: SequencerArg):
-            tree = make_sequence(*args)
-            return SfgMethod(
-                name,
-                tree,
-                return_type=create_type(returns),
-                inline=inline,
-                const=const,
-            )
-
-        return sequencer
+        return SfgClassComposer.MethodSequencer(name, returns, inline, const)
 
     #   INTERNALS
 
     def _class(self, class_name: str, keyword: SfgClassKeyword, bases: Sequence[str]):
-        if self._ctx.get_class(class_name) is not None:
-            raise ValueError(f"Class or struct {class_name} already exists.")
+        if self._cursor.get_entity(class_name) is not None:
+            raise ValueError(
+                f"Another entity with name {class_name} already exists in the current namespace."
+            )
 
-        cls = SfgClass(class_name, class_keyword=keyword, bases=bases)
-        self._ctx.add_class(cls)
+        cls = SfgClass(
+            class_name,
+            self._cursor.current_namespace,
+            class_keyword=keyword,
+            bases=bases,
+        )
+        self._cursor.add_entity(cls)
 
         def sequencer(
             *args: (
-                SfgClassComposer.VisibilityContext
-                | SfgClassMember
+                SfgClassComposer.VisibilityBlockSequencer
+                | SfgClassComposer.MethodSequencer
                 | SfgClassComposer.ConstructorBuilder
                 | VarLike
                 | str
             ),
         ):
-            default_ended = False
-
-            for arg in args:
-                if isinstance(arg, SfgClassComposer.VisibilityContext):
-                    default_ended = True
-                    arg.resolve(cls)
-                elif isinstance(
-                    arg,
-                    (
-                        SfgClassMember,
-                        SfgClassComposer.ConstructorBuilder,
-                        str,
-                    )
-                    + _VarLike,
-                ):
-                    if default_ended:
-                        raise SfgException(
-                            "Composer Syntax Error: "
-                            "Cannot add members with default visibility after a visibility block."
-                        )
-                    else:
-                        cls.default.append_member(self._resolve_member(arg))
+            default_vis_sequencer = SfgClassComposer.VisibilityBlockSequencer(
+                SfgVisibility.DEFAULT
+            )
+
+            def argfilter(arg):
+                return not isinstance(arg, SfgClassComposer.VisibilityBlockSequencer)
+
+            default_vis_args = takewhile(
+                argfilter,
+                args,
+            )
+            default_vis_sequencer(*default_vis_args)._resolve(self._ctx, cls)  # type: ignore
+
+            for arg in dropwhile(argfilter, args):
+                if isinstance(arg, SfgClassComposer.VisibilityBlockSequencer):
+                    arg._resolve(self._ctx, cls)
                 else:
-                    raise SfgException(f"{arg} is not a valid class member.")
+                    raise SfgException(
+                        "Composer Syntax Error: "
+                        "Cannot add members with default visibility after a visibility block."
+                    )
 
-        return sequencer
+            self._cursor.write_header(SfgEntityDef(cls))
 
-    @staticmethod
-    def _resolve_member(
-        arg: SfgClassMember | SfgClassComposer.ConstructorBuilder | VarLike | str,
-    ) -> SfgClassMember:
-        match arg:
-            case _ if isinstance(arg, _VarLike):
-                var = asvar(arg)
-                return SfgMemberVariable(var.name, var.dtype)
-            case str():
-                return SfgInClassDefinition(arg)
-            case SfgClassComposer.ConstructorBuilder():
-                return arg.resolve()
-            case SfgClassMember():
-                return arg
-            case _:
-                raise ValueError(f"Invalid class member: {arg}")
+        return sequencer
diff --git a/src/pystencilssfg/composer/mixin.py b/src/pystencilssfg/composer/mixin.py
index 3ee8efa61227184686001045bf3f8cb23525bf02..34b1c5856a3b923f4b15939110bf3bfbc0ba5970 100644
--- a/src/pystencilssfg/composer/mixin.py
+++ b/src/pystencilssfg/composer/mixin.py
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from ..context import SfgContext
+from ..context import SfgContext, SfgCursor
 from .basic_composer import SfgBasicComposer
 
 
@@ -14,6 +14,7 @@ class SfgComposerMixIn:
 
     def __init__(self) -> None:
         self._ctx: SfgContext
+        self._cursor: SfgCursor
 
     @property
     def _composer(self) -> SfgBasicComposer:
diff --git a/src/pystencilssfg/context.py b/src/pystencilssfg/context.py
index 577dcbd0a0d6b2d55176f92aae11213971d3da86..48d0720c9927542bdca291c206f28f55f9172437 100644
--- a/src/pystencilssfg/context.py
+++ b/src/pystencilssfg/context.py
@@ -5,11 +5,10 @@ from .config import CodeStyle
 from .ir.source_components import (
     SfgSourceFile,
     SfgNamespace,
-    SfgKernelNamespace,
     SfgNamespaceBlock,
     SfgNamespaceElement,
     SfgCodeEntity,
-    SfgClass,
+    SfgGlobalNamespace,
 )
 from .exceptions import SfgException
 
@@ -37,9 +36,14 @@ class SfgContext:
         self._header_file = header_file
         self._impl_file = impl_file
 
-        self._entities: dict[str, SfgCodeEntity] = dict()
+        self._global_namespace = SfgGlobalNamespace()
 
-        self._cursor: SfgCursor
+        current_ns: SfgNamespace = self._global_namespace
+        if outer_namespace is not None:
+            for token in outer_namespace.split("::"):
+                current_ns = SfgNamespace(token, current_ns)
+
+        self._cursor = SfgCursor(self, current_ns)
 
     @property
     def argv(self) -> Sequence[str]:
@@ -85,28 +89,18 @@ class SfgContext:
         if self._impl_file is not None:
             yield self._impl_file
 
-    def get_entity(self, fqname: str) -> SfgCodeEntity | None:
-        #   TODO: Only track top-level entities here, traverse namespaces to find qualified entities
-        return self._entities.get(fqname, None)
-
-    def add_entity(self, entity: SfgCodeEntity) -> None:
-        fqname = entity.fqname
-        if fqname in self._entities:
-            raise ValueError(f"Another entity with name {fqname} already exists")
-        self._entities[fqname] = entity
+    @property
+    def global_namespace(self) -> SfgNamespace:
+        return self._global_namespace
 
 
 class SfgCursor:
     """Cursor that tracks the current location in the source file(s) during execution of the generator script."""
 
-    def __init__(self, ctx: SfgContext, namespace: str | None = None) -> None:
+    def __init__(self, ctx: SfgContext, namespace: SfgNamespace) -> None:
         self._ctx = ctx
 
-        self._cur_namespace: SfgNamespace | None
-        if namespace is not None:
-            self._cur_namespace = ctx.get_namespace(namespace)
-        else:
-            self._cur_namespace = None
+        self._cur_namespace: SfgNamespace = namespace
 
         self._loc: dict[SfgSourceFile, list[SfgNamespaceElement]]
         for f in self._ctx.files:
@@ -120,9 +114,15 @@ class SfgCursor:
     #   TODO: Enter and exit namespace blocks
 
     @property
-    def current_namespace(self) -> SfgNamespace | None:
+    def current_namespace(self) -> SfgNamespace:
         return self._cur_namespace
 
+    def get_entity(self, name: str) -> SfgCodeEntity | None:
+        return self._cur_namespace.get_entity(name)
+
+    def add_entity(self, entity: SfgCodeEntity):
+        self._cur_namespace.add_entity(entity)
+
     def write_header(self, elem: SfgNamespaceElement) -> None:
         self._loc[self._ctx.header_file].append(elem)
 
diff --git a/src/pystencilssfg/ir/analysis.py b/src/pystencilssfg/ir/analysis.py
index 0b42594033da16efbde3ab8da3433dfcad03a097..c550975cd0b5750f980f52145cbd2ee7e5a3f93a 100644
--- a/src/pystencilssfg/ir/analysis.py
+++ b/src/pystencilssfg/ir/analysis.py
@@ -15,7 +15,6 @@ def collect_includes(obj: Any) -> set[HeaderFile]:
         SfgClass,
         SfgConstructor,
         SfgMemberVariable,
-        SfgInClassDefinition,
     )
 
     match obj:
@@ -58,9 +57,6 @@ def collect_includes(obj: Any) -> set[HeaderFile]:
         case SfgMemberVariable():
             return includes(obj)
 
-        case SfgInClassDefinition():
-            return set()
-
         case _:
             raise SfgException(
                 f"Can't collect includes from object of type {type(obj)}"
diff --git a/src/pystencilssfg/ir/call_tree.py b/src/pystencilssfg/ir/call_tree.py
index a5d2c5a35b1795817305515b74797c2bf3f2b91b..9a29f2f0715d18878f7a84926504c51ebf78c213 100644
--- a/src/pystencilssfg/ir/call_tree.py
+++ b/src/pystencilssfg/ir/call_tree.py
@@ -210,7 +210,7 @@ class SfgKernelCallNode(SfgCallTreeLeaf):
 
     def get_code(self, ctx: SfgContext) -> str:
         ast_params = self._kernel_handle.parameters
-        fnc_name = self._kernel_handle.fully_qualified_name
+        fnc_name = self._kernel_handle.fqname
         call_parameters = ", ".join([p.name for p in ast_params])
 
         return f"{fnc_name}({call_parameters});"
@@ -228,7 +228,7 @@ class SfgCudaKernelInvocation(SfgCallTreeLeaf):
         from pystencils import Target
         from pystencils.codegen import GpuKernel
 
-        func = kernel_handle.get_kernel_function()
+        func = kernel_handle.get_kernel()
         if not (isinstance(func, GpuKernel) and func.target == Target.CUDA):
             raise ValueError(
                 "An `SfgCudaKernelInvocation` node can only call a CUDA kernel."
@@ -247,7 +247,7 @@ class SfgCudaKernelInvocation(SfgCallTreeLeaf):
 
     def get_code(self, ctx: SfgContext) -> str:
         ast_params = self._kernel_handle.parameters
-        fnc_name = self._kernel_handle.fully_qualified_name
+        fnc_name = self._kernel_handle.fqname
         call_parameters = ", ".join([p.name for p in ast_params])
 
         grid_args = [self._num_blocks, self._threads_per_block]
diff --git a/src/pystencilssfg/ir/source_components.py b/src/pystencilssfg/ir/source_components.py
index d8fb0f57e5a91b55b6e5fa44115cb18e50794d22..15b27fb428b3a66827185d550b93d0bab78475f8 100644
--- a/src/pystencilssfg/ir/source_components.py
+++ b/src/pystencilssfg/ir/source_components.py
@@ -39,9 +39,9 @@ class SfgCodeEntity:
     Each code entity has a name and an optional enclosing namespace.
     """
 
-    def __init__(self, name: str, parent_namespace: SfgNamespace | None) -> None:
+    def __init__(self, name: str, parent_namespace: SfgNamespace) -> None:
         self._name = name
-        self._namespace: SfgNamespace | None = parent_namespace
+        self._namespace: SfgNamespace = parent_namespace
 
     @property
     def name(self) -> str:
@@ -51,7 +51,7 @@ class SfgCodeEntity:
     @property
     def fqname(self) -> str:
         """Fully qualified name of this entity"""
-        if self._namespace is not None:
+        if not isinstance(self._namespace, SfgGlobalNamespace):
             return self._namespace.fqname + "::" + self._name
         else:
             return self._name
@@ -73,7 +73,31 @@ class SfgNamespace(SfgCodeEntity):
         parent: Parent namespace enclosing this namespace
     """
 
-    #   TODO: Namespaces must keep track of their child entities
+    def __init__(self, name: str, parent_namespace: SfgNamespace) -> None:
+        super().__init__(name, parent_namespace)
+
+        self._entities: dict[str, SfgCodeEntity] = dict()
+
+    def get_entity(self, name: str) -> SfgCodeEntity | None:
+        return self._entities.get(name, None)
+
+    def add_entity(self, entity: SfgCodeEntity):
+        if entity.name in self._entities:
+            raise ValueError(
+                f"Another entity with the name {entity.fqname} already exists"
+            )
+        self._entities[entity.name] = entity
+
+
+class SfgGlobalNamespace(SfgNamespace):
+    """The C++ global namespace."""
+
+    def __init__(self) -> None:
+        super().__init__("", self)
+
+    @property
+    def fqname(self) -> str:
+        return ""
 
 
 class SfgKernelHandle(SfgCodeEntity):
@@ -117,9 +141,9 @@ class SfgKernelHandle(SfgCodeEntity):
 class SfgKernelNamespace(SfgNamespace):
     """A namespace grouping together a number of kernels."""
 
-    def __init__(self, name: str, parent: SfgNamespace | None):
+    def __init__(self, name: str, parent: SfgNamespace):
         super().__init__(name, parent)
-        self._kernels: dict[str, SfgKernelHandle] = []
+        self._kernels: dict[str, SfgKernelHandle] = dict()
 
     @property
     def name(self):
@@ -200,7 +224,7 @@ class SfgFunction(SfgCodeEntity):
     def __init__(
         self,
         name: str,
-        namespace: SfgNamespace | None,
+        namespace: SfgNamespace,
         tree: SfgCallTreeNode,
         return_type: PsType = void,
         inline: bool = False,
@@ -272,8 +296,8 @@ class SfgClassKeyword(Enum):
 class SfgClassMember(ABC):
     """Base class for class member entities"""
 
-    def __init__(self) -> None:
-        self._cls: SfgClass | None = None
+    def __init__(self, cls: SfgClass) -> None:
+        self._cls: SfgClass = cls
         self._visibility: SfgVisibility | None = None
 
     @property
@@ -290,26 +314,13 @@ class SfgClassMember(ABC):
             )
         return self._visibility
 
-    @property
-    def is_bound(self) -> bool:
-        return self._cls is not None
-
-    def _bind(self, cls: SfgClass, vis: SfgVisibility):
-        if self.is_bound:
-            raise SfgException(
-                f"Binding {self} to class {cls.class_name} failed: "
-                f"{self} was already bound to {self.owning_class.class_name}"
-            )
-        self._cls = cls
-        self._vis = vis
-
 
 class SfgMemberVariable(SfgVar, SfgClassMember):
     """Variable that is a field of a class"""
 
-    def __init__(self, name: str, dtype: PsType):
+    def __init__(self, name: str, dtype: PsType, cls: SfgClass):
         SfgVar.__init__(self, name, dtype)
-        SfgClassMember.__init__(self)
+        SfgClassMember.__init__(self, cls)
 
 
 class SfgMethod(SfgClassMember):
@@ -320,12 +331,13 @@ class SfgMethod(SfgClassMember):
     def __init__(
         self,
         name: str,
+        cls: SfgClass,
         tree: SfgCallTreeNode,
         return_type: PsType = void,
         inline: bool = False,
         const: bool = False,
     ):
-        super().__init__()
+        super().__init__(cls)
 
         self._name = name
         self._tree = tree
@@ -368,11 +380,12 @@ class SfgConstructor(SfgClassMember):
 
     def __init__(
         self,
+        cls: SfgClass,
         parameters: Sequence[SfgVar] = (),
         initializers: Sequence[str] = (),
         body: str = "",
     ):
-        SfgClassMember.__init__(self)
+        super().__init__(cls)
         self._parameters = tuple(parameters)
         self._initializers = tuple(initializers)
         self._body = body
@@ -409,7 +422,7 @@ class SfgClass(SfgCodeEntity):
     def __init__(
         self,
         name: str,
-        namespace: SfgNamespace | None,
+        namespace: SfgNamespace,
         class_keyword: SfgClassKeyword = SfgClassKeyword.CLASS,
         bases: Sequence[str] = (),
     ):
@@ -422,7 +435,6 @@ class SfgClass(SfgCodeEntity):
         self._bases_classes = tuple(bases)
 
         self._default_block = SfgVisibilityBlock(SfgVisibility.DEFAULT)
-        self._default_block._bind(self)
         self._blocks = [self._default_block]
 
         self._constructors: list[SfgConstructor] = []
@@ -451,14 +463,10 @@ class SfgClass(SfgCodeEntity):
             raise SfgException(
                 "Can't add another block with DEFAULT visibility to a class. Use `.default` instead."
             )
-
-        block._bind(self)
-        for m in block.members():
-            self._add_member(m, block.visibility)
         self._blocks.append(block)
 
-    def visibility_blocks(self) -> Generator[SfgVisibilityBlock, None, None]:
-        yield from self._blocks
+    def visibility_blocks(self) -> tuple[SfgVisibilityBlock, ...]:
+        return tuple(self._blocks)
 
     def members(
         self, visibility: SfgVisibility | None = None
@@ -497,26 +505,16 @@ class SfgClass(SfgCodeEntity):
         else:
             yield from self._methods
 
-    # PRIVATE
-
-    def _add_member(self, member: SfgClassMember, vis: SfgVisibility):
+    def add_member(self, member: SfgClassMember, vis: SfgVisibility):
         if isinstance(member, SfgConstructor):
-            self._add_constructor(member)
+            self._constructors.append(member)
         elif isinstance(member, SfgMemberVariable):
             self._add_member_variable(member)
         elif isinstance(member, SfgMethod):
-            self._add_method(member)
+            self._methods.append(member)
         else:
             raise SfgException(f"{member} is not a valid class member.")
 
-        member._bind(self, vis)
-
-    def _add_constructor(self, constr: SfgConstructor):
-        self._constructors.append(constr)
-
-    def _add_method(self, method: SfgMethod):
-        self._methods.append(method)
-
     def _add_member_variable(self, variable: SfgMemberVariable):
         if variable.name in self._member_vars:
             raise SfgException(
@@ -598,22 +596,13 @@ class SfgVisibilityBlock:
     def visibility(self) -> SfgVisibility:
         return self._vis
 
-    def append_member(self, element: SfgClassBodyElement):
-        if isinstance(element, (SfgEntityDecl, SfgEntityDef)):
-            member = element.entity
-        elif isinstance(element, SfgClassMember):
-            member = element
-        else:
-            member = None
-
-        if self._cls is not None and member is not None:
-            self._cls._add_member(member, self._vis)
-
-        self._elements.append(element)
-
     @property
-    def elements(self) -> tuple[SfgClassBodyElement, ...]:
-        return tuple(self._elements)
+    def elements(self) -> list[SfgClassBodyElement]:
+        return self._elements
+
+    @elements.setter
+    def elements(self, elems: Iterable[SfgClassBodyElement]):
+        self._elements = list(elems)
 
     def members(self) -> Generator[SfgClassMember, None, None]:
         for elem in self._elements:
@@ -623,18 +612,6 @@ class SfgVisibilityBlock:
                 case SfgMemberVariable():
                     yield elem
 
-    @property
-    def is_bound(self) -> bool:
-        return self._cls is not None
-
-    def _bind(self, cls: SfgClass):
-        if self._cls is not None:
-            raise SfgException(
-                f"Binding visibility block to class {cls.class_name} failed: "
-                f"was already bound to {self._cls.class_name}"
-            )
-        self._cls = cls
-
 
 class SfgNamespaceBlock:
     """A C++ namespace.