Overloads and overrides#

An overload is one operation with several accepted parameter packs. Nupp uses the same exact-one selection rule for callable intersections, repeated method bodies, and constructors. Method overloads keep separate bodies and compile to direct calls; they are not runtime dispatch functions hidden behind one name.

@override answers a different question. It says that one method body replaces an inherited interface default with the same parameter pack. Repeated names create overloads automatically, so there is no @overload annotation.

Callable intersections#

An intersection containing only function types is an overload contract:

The checker infers the complete argument pack once, probes every member without changing ownership or borrow state, and accepts the call only when exactly one member survives. Declaration order does not break a tie and there is no best-match ranking.

A callable intersection describes one callable value with several contracts. It does not itself create several implementations. Repeated method declarations are what give several bodies to one method name.

Separate method bodies#

Write each method implementation under the same name:

The visible type of decode is an intersection of its callable signatures. The compiler also retains two method entries: each entry has its own body, effects, source definition, and stable hidden runtime slot. Once the checker selects an entry, code generation calls that slot directly with ordinary Lua colon semantics. The receiver is evaluated once and no dispatcher runs.

A method group is not one field value#

There is no runtime value corresponding to the source name decoder.decode:

Write an adapter when a callback needs one selected operation:

The adapter is explicit about which parameter pack it exposes and remains an ordinary first-class Lua function.

Ambiguous and rejected calls#

An any argument may leave several entries possible:

An explicit cast selects the intended entry:

Subtype overlap can be ambiguous too. An integer satisfies both integer and number, and Nupp does not guess that the narrower spelling was preferred:

No surviving member is NUPP2125:

Parameter packs, not results, select#

Two bodies cannot differ only by return type:

The call has to choose a body before it can obtain a result, so an expected result type cannot resolve this ambiguity. Parameter ownership modes, generic bounds, and pack tails participate in entry identity; return packs do not.

Bodyless interface contracts#

An interface with no implementation writes the method as a callable intersection field. Matching record bodies use the same signature-derived slots:

This is implementation, not replacement: the interface supplied no body, so these methods do not use @override. Every contract entry needs a compatible record body:

Default implementations and @override#

An interface may instead provide bodies. A record inherits every default entry it does not replace:

@override matches the exact parameter pack. Here it replaces only the string entry; the integer default remains inherited. Omitting @override from the string body is NUPP2118, because replacing inherited behavior must be explicit. Putting it on a parameter pack with no inherited body is also NUPP2118:

A record may replace one default and add another overload. Only the replacement uses @override:

Two interfaces can contribute different default entries under the same source name. Their distinct parameter packs form one inherited overload group:

If two interfaces provide the same parameter pack, they provide competing bodies for one entry. The record must write a compatible body to resolve the conflict.

Generic method overloads#

Generic declaration parameters remain part of each entry and specialize at the call site without changing its runtime slot:

The compiler selects using the specialized signatures but invokes the bodies' stable declaration slots. Calls through a generic interface use the same rule.

Constructor overloads#

Constructors already have separate bodies, so repeating constructor declares the overload group:

new Value(...) applies the same exact-one selection rule and directly invokes the selected constructor body. Duplicate constructor parameter packs are NUPP2208.

Untyped callers need an explicit facade#

The hidden method slots are compiler ABI, not source-level Lua member names. Untyped Lua therefore cannot call decoder:decode(value) on an overloaded record. Export an ordinary function that performs an explicit runtime decision when a dynamic boundary needs one:

That dispatcher exists because the program asked for a dynamic facade. Typed method calls do not pay for it.

Diagnostics#

Code Meaning here
NUPP2125 No callable-intersection member accepts the argument pack.
NUPP2126 Several members accept it, or an overloaded method was read as one field value.
NUPP2118 A method parameter pack is duplicated, an interface entry is missing or incompatible, or @override does not match exactly one inherited default.
NUPP2208 Constructor overloads duplicate a parameter pack or violate constructor integrity.

For the underlying intersection relation, including capability composition and provable emptiness, see Intersection types. For general interface inheritance and runtime defaults, see Interfaces.