13
$\begingroup$

Extension methods and Uniform Function Call Syntax (UFCS) are two different ways of letting you write a method call like foo.bar() without bar being a method originally defined on foo.

Extension methods are methods added to a type outside of the type's original definition. They let you add a .sum() method on a type such as List even if you didn't define List yourself. This .sum() extension method, however, is not a free function that can be passed around. It must be called on a List object. C#, Kotlin, and many other languages have extension methods.

UFCS is very similar, except there's no special extension methods that are treated differently. You can take a free function that would normally be called like foo(bar, baz) and instead call it like bar.foo(baz). Ideally, this would also work the other way: a method .foo() on some object bar should be able to be called as foo(bar) too (although D, a language with UFCS, doesn't fully support this).

My question is this: what are the advantages and disadvantages of extension methods and uniform function call syntax? What trade-offs are made when choosing one over the other, and in what circumstance would you prefer one over the other?

$\endgroup$

3 Answers 3

7
$\begingroup$

The most important difference is that extension methods do not require that the language has overloading, while UFCS is built on top of overloading.

$\endgroup$
4
  • $\begingroup$ This allowed Kotlin to use them to great effect to build their own collections library on top of Java collections classes that they cannot add methods to. $\endgroup$ Jul 20, 2023 at 23:44
  • $\begingroup$ This makes it sound as if UFCS could not be implemented in a dynamically typed language, but I really can't see a reason for that. It would just require some rules for when to treat bar.foo as an attribute lookup and when to treat it as a sugared call to foo. $\endgroup$ Jul 27, 2023 at 22:31
  • $\begingroup$ @KarlKnechtel consider the function foo(bar, baz), then we must at least assume that this function is different from foo(abc, baz) i.e. there is a concept of overloading or the use is very limited as we cannot reuse any function name once it is defined. $\endgroup$
    – Nuoji
    Aug 2, 2023 at 14:20
  • $\begingroup$ @KarlKnechtel Overloading is a dynamically-typed language is just called "multimethods". Julia designs its entire semantics around multimethods, and it works quite well in practice. $\endgroup$ Aug 24, 2023 at 1:33
4
$\begingroup$

New conformances

In languages with nominal rather than structural typing, UFCS doesn't let you add a new protocol conformance to an existing type, but extensions can, e.g. (Swift):

protocol MyNumericThing {
  func add(_ other: Self) -> Self
}

extension Int: MyNumericThing {
  func add(_ other: Int) -> Int { self + other }
}

Of course, this comes with the danger of retroactive conformances, which you can read more about here.

$\endgroup$
3
$\begingroup$

Freedom in calling syntax

Without UFCS, you have to call a procedure/method with the syntax that the author wanted you to use. With UFCS, you can freely decide which syntax works better in your context.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .