Interfaces, Enums, and Annotations
Beyond regular classes, Klyn provides interfaces for contracts, enums for symbolic states, and annotations for metadata. These three forms are small but important pieces of the language.
Interfaces
interface DoSomething:
public doSomething() as Int
public abstract doSomethingElse() as Int
public static version() as Int:
return 1
Instance methods declared by an interface define abstract contracts: they cannot be private or define a body. Static interface methods may define a body when the operation belongs to the interface itself rather than to implementing instances.
Enums
enum Color:
RED
GREEN
BLUE
enum ColorName:
RED = "red"
GREEN = "green"
BLUE = "blue"
public readonly property value as String
public ColorName(value as String):
this.value = value
Simple enums receive integer values by default. You can also define explicit payload values and
properties when the enum needs richer data. Explicit values must be compile-time Int
or String constants, every state uses the same value type, and two states cannot share
the same value.
An enum may also belong to a class. Outside that class, qualify its name with the declaring class. Enums with the same short name in different classes remain distinct types.
class Job:
public enum State:
READY
DONE
state as Job.State = Job.State.READY
assert state.value == 0
Annotations
annotation Deprecated:
pass
@Deprecated
class LegacyApi:
pass
Annotations attach metadata to declarations. They are commonly used for testing, tooling, and API lifecycle markers.
An annotation applies to the next type or class-member declaration in the same block.
Blank lines and comments may separate it from that declaration. It cannot be attached to
pass, another statement, or a free function declared with def.
An unsupported target or an annotation left without a declaration raises
SyntaxError; it never decorates a later declaration past that boundary.
Annotations with Arguments
annotation TestClass:
public readonly property category as String = null
public TestClass(category as String):
this.category = category
@TestClass(category="Unit")
class MathTests:
pass
Annotation arguments use the same named-argument style you see in ordinary calls.
Fully Qualified Annotation Names
@klyn.unittest.TestClass
class DemoTests:
pass
A fully qualified annotation does not import its package. Use
@klyn.unittest.Test wherever no import klyn.unittest
is present; using that qualified name once never makes @Test
visible elsewhere in the file.
Qualified annotation names are useful when you want to avoid ambiguity or do not want an extra import for a short file.
Test Timeouts
The standard @Test annotation accepts a per-method timeout in milliseconds.
@TestClass accepts the same property for the complete class lifecycle. A value of
0u disables the corresponding limit.
import klyn.unittest
@TestClass(timeout=2000)
public class ParserTests:
@Test(timeout=250)
public finishesQuickly():
assert compute() > 0
@Test(timeout=1000, expected=ValueException)
public rejectsInvalidInput():
parseValue("invalid")
The class budget covers construction and all setup, test and teardown methods. Compilation is not part of that budget. If a method timeout is longer than the remaining class budget, the class deadline remains authoritative.