Traits

A trait is a reusable group of methods (and, in Pharo, slots) that can be composed into classes, independent of the inheritance hierarchy.

31.1 What traits are

A trait is a reusable group of methods (and, in Pharo, slots) that can be composed into classes, independent of the inheritance hierarchy. Traits solve the problem of sharing behavior across unrelated classes without multiple inheritance. Introduced by Schärli, Ducasse, Nierstrasz, and Black (2003); used heavily in Pharo's own kernel.

31.2 Defining and using a trait

Classic syntax: Object subclass: #Person uses: TGreetable instanceVariableNames: 'name' classVariableNames: '' package: 'Traits-Demo'.

Trait << #TGreetable
    slots: {};
    package: 'Traits-Demo'

TGreetable >> greeting
    ^ 'Hello, I am ' , self displayName

TGreetable >> displayName
    ^ self explicitRequirement          "the using class must implement this"

Object << #Person
    traits: { TGreetable };
    slots: { #name };
    package: 'Traits-Demo'

Person >> name: aString
    name := aString

Person >> displayName
    ^ name
(Person new name: 'Ada') greeting.     "→ 'Hello, I am Ada'"
Person usesTrait: TGreetable.         "→ true"

31.3 Composition operators

Use both traits (conflicting methods must be resolved) TA - { #foo } Exclude method foo from TA TA @ { #bar -> #foo }

Alias: make foo also available as bar TA -- { #slot } Remove a slot (stateful traits)

Rules: methods defined in the class override trait methods; trait methods override inherited methods; conflicts between traits must be resolved explicitly (exclusion, alias, or defining the method in the class).

Object << #Robot
    traits: { TGreetable + TComparableByName - { #displayName } };
    slots: { #serial };
    package: 'Traits-Demo'

31.4 Stateful traits and class-side traits

Pharo traits can declare slots (Trait << #TCounter slots: { #count }), and a trait's class side (TCounter classTrait) adds class-side methods. Examples in the kernel: TComparable, TAssertable, TEmpty, TSize.

31.5 Traits in other dialects

Squeak has stateless traits (since 3.9); Cuis does not use them; VisualWorks, VA Smalltalk, and GemStone don't support traits natively. Use them where available, but don't overuse — a plain helper object is often clearer.