New Issue: IFC: how to write an interface-constrained function min() ?

17842, "vasslitvinov", "IFC: how to write an interface-constrained function min() ?", "2021-05-27T22:49:16Z"

main issue: #8629     related: #17262 #17540 #17599

Splitting this issue from CG: semantics of 'implements' with a class · Issue #17262 · chapel-lang/chapel · GitHub

Background

If I have a "comparable" interface, I can write a min() function that takes two comparables:

interface Comparable {
  operator <(lhs: Self, rhs: Self): bool;
}

proc minFn(x: ?T, y: T): T
  where T implements Comparable
{
  if x < y then return x; else return y;
}

This works fine if I am dealing just with numbers. This even works with POD records. (It escapes me However, it hits an error when I implement Comparable for an owned class.

Questions

This leads me to these questions:

  • Is it reasonable for a user to write the above code?
  • If so, what should be the compilation outcome - success, error, what error?
  • How to make the above code work with owned ?

Proposal how to handle the code as-is

I suggest that the above code is reasonable and should compile successfully.

I also suggest that it should generate an EARLY-checking error message when there is a possibility of minFn to be invoked on an owned object. For example, if I declare implements Comparable(owned MyClass). In such a case the compiler currently issues a late-checking error, i.e., only if the minFn() is invoked on owned MyClass.

One way to get there is to introduce an interface denoting a "normal" type - i.e. a type that can be assigned, copied, etc. Each interface formal could be implicitly required to satisfy this interface unless opted out. If the interface constraints of minFn() allow non-"normal" argument types, the compiler should report an early error. owned types would not be able to implement this normal-type interface.

How to make minFn() accept owned

One way is to have the user rewrite it with in-intents:

proc minFn(in x: ?T, in y: T): T where .......
{
  if x < y then return x; else return y;
}

This works, however it is perhaps not the intended behavior because this minFn takes over the ownership of both arguments then returns one and deletes the other.

Another way is to have the Comparable interface be implemented for a borrowed type, then allow implicit conversions, see #17540, when operator < or proc minFn are passed class types.