4
$\begingroup$

Swift allows protocols (called "interfaces" or "traits" in other languages) to require initializers and static members. This allows things like this:

func canAddWithoutOverflow<T: FixedWidthInteger>(_ x: T, _ y: T) -> Bool {
  precondition(x >= 0)
  let roomToAdd = T.max - x // Notice the static member "T.max" here, from FixedWidthInteger
                            // https://developer.apple.com/documentation/swift/fixedwidthinteger/max
  return y <= roomToAdd
}

Other languages, like C# and Java, don't do this. What are some advantages and disadvantages to having this?

$\endgroup$
1
  • $\begingroup$ I find this use of the word "static" amusing, since it means that invocations of such methods through the interface aren't statically bound after all. $\endgroup$
    – kaya3
    Commented Aug 28, 2023 at 18:53

2 Answers 2

7
$\begingroup$

Advantage: Dynamic instantiation

In functions without static methods on interfaces, it is impossible to construct an instance of a class without naming each individual class. However, if you allow static methods you can re-use instantiation logic for all implementers of a class.

trait K{fn new(u32)->K};

fn createFactory<T: K>()->Box<dyn Fn(u32)->Box<dyn K>>{
    |x|T::new(x)
}

This is especially useful if you want to eg. instantiate an array of many values of a specific class with similar logic for many different classes.

$\endgroup$
2
$\begingroup$

Tyr actually has both, classical static members that are associated with the type and, thus, not inherited and members associated with the class itself. The latter ones behave like the static members in the question. In essence, they are instance members that use the runtime type information as the underlying object.

Both serve different use cases. Static members are mostly stateless functions and constants associated with the surrounding type. There is no reason not to allow this for interfaces.

Class members are used to group properties that an instance of a type has but that does not depend on the instance. Something like a human-readable type name or widget name (field) or a constructor with a certain set of arguments (function).

The factory functions are an advantage over an implicit default constructor logic that most languages resort to.

The class fields are in many ways cheaper than using a function with a constant result as one would in Java.

A downside of class members over type members is that accessing them is more expensive. In the current Tyr implementation, a type member uses direct access that works well with optimization. A class member from a class uses a virtual member access which is barely optimized and a class member from an interface uses an imember access which I never saw to get optimized out in realistic code. Also, in Tyr, class members require storage in each class inheriting them even if they inherit an unmodified copy from the parent class.

A downside of having, both, class and type members is that it makes the language more complex, harder to learn and harder to implement. One would think that the three kind of members (object, class, type) share a lot of implementation logic, but this is in fact not the case in most phases of the compiler.

$\endgroup$

You must log in to answer this question.

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