What is the difference between a function and a method in EK9?

← Functions and Methods · Ref: Q596

Functions and methods in EK9 are fundamentally different constructs. Functions are stateless first-class types defined at module level. Methods are bound to the state of a class, trait, or record.

FUNCTIONS ARE TYPES

Functions in EK9 are declared in a 'defines function' block at module level. Every function is a nominal type with its own identity. Functions can be stored in variables, passed as arguments, returned from other functions, and collected in lists. Functions do NOT have access to any class state because they exist outside of any class.

METHODS ARE BOUND TO STATE

Methods are declared inside a class, trait, or record. They have access to the properties of their enclosing type via 'this'. Methods can have visibility modifiers (public, protected, private). Methods can be overridden in subclasses. Methods cannot be stored in variables independently of their object.

SYNTAX COMPARISON

Both use '->' for parameters and '<-' for returns. Both can be marked 'as pure'. The syntax is deliberately similar so developers focus on the conceptual difference (stateless vs stateful) rather than syntactic differences.

FUNCTION ADVANTAGES

Functions are testable in isolation (no object setup needed). Functions compose naturally (pass one function to another). Functions enable polymorphism without classes (via abstract function types). Functions enforce statelessness, which aids reasoning and parallelism.

METHOD ADVANTAGES

Methods encapsulate state. Methods support inheritance hierarchies. Methods support dispatching on the receiver type. Methods enable the standard OOP patterns (encapsulation, polymorphism via classes).

WHEN TO CHOOSE

Use functions for pure computations, transformations, and pipeline stages. Use methods when behaviour is intrinsically tied to object state. Use abstract functions when you need callable polymorphism without classes.

See Q49 for function basics. See Q93 for class and method basics. See Q105 for method dispatch in classes. See Q255 for cost-based method resolution. See Q597 for function parameter patterns. See Q600 for method overloading vs function dispatching.

Example

defines module qa.functionsAndMethods.functionVsMethod

  defines function

    //Function: stateless, at module level, first-class type
    formatName() as pure
      ->
        first as String
        last as String
      <- result as String: `${last}, ${first}`

    //Abstract function: defines a callable contract
    Transformer as pure abstract
      -> input as String
      <- output as String?

    //Named function implementing abstract type
    UpperTransformer is Transformer as pure
      -> input as String
      <- output as String: input.upperCase()

  defines class

    //Class with methods: methods access 'this' state
    Greeter
      prefix <- String()

      Greeter()
        -> prefix as String
        this.prefix: prefix

      //Method: accesses class state (prefix)
      greet()
        -> name as String
        <- message as String: `${prefix} ${name}`

      default operator ?

  defines program

    FunctionVsMethodDemo()
      stdout <- Stdout()

      // === FUNCTION: stateless, no object needed ===
      stdout.println(formatName("Steve", "Limb"))

      // === METHOD: requires object with state ===
      greeter <- Greeter("Hello")
      stdout.println(greeter.greet("World"))

      // === FUNCTION AS TYPE: store in variable ===
      transformer as Transformer: UpperTransformer
      stdout.println(transformer("hello world"))

      // === FUNCTIONS IN LISTS: polymorphic iteration ===
      lower <- () is Transformer as pure (output:=? input.lowerCase())
      transformers <- [UpperTransformer, lower]
      for item in transformers
        stdout.println(item("Mixed Case"))

Common mistakes

E07520 — When a class inherits operator ? from a base type, the implementation must use the 'override' keyword (or 'default' for auto-generated). Declaring bare 'operator ?' triggers E07520 because operator semantics require a Boolean return. See ek9 -h E07520 for details.

Incorrect:

operator ?

Correct:

default operator ?

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

stdout.println(formatName("Steve", "Limb").toUpperCase())

Correct:

stdout.println(formatName("Steve", "Limb"))
Other ways to ask this
  • How do functions differ from methods in EK9?
  • When should I use a function instead of a method in EK9?
  • Are functions and methods interchangeable in EK9?

Coming from another language?

Java: all functions must live inside classes as static methods or instance methods, no standalone functions, functional interfaces (SAM) are a workaround. Python: def creates functions at module level or methods inside classes, no formal distinction in type system. JavaScript: functions are standalone, methods are properties of objects, 'this' binding is confusing. Rust: fn defines standalone functions, impl blocks add methods to structs, methods take &self. Go: functions are standalone, methods use receiver syntax, no inheritance. Kotlin: top-level functions exist alongside class methods, extension functions blur the line. Swift: free functions and methods, protocol methods. EK9: functions are first-class nominal types at module level, methods are bound to class/trait/record state, both use identical syntax, functions can form type hierarchies via abstract.

Keywords: first-class, class, method, function, type, stateless, state, parameter, stateful, bound, difference, module