Pre-RFC: Named arguments

Sure. Option A, the one I recommend, is that function types do not have labels. The type of fn removeAll(&mut self, equalTo value: T) and the type of fn append(&mut self, _ value: T) are both fn(&mut Self, T).

Option B is to keep the labels in the type, giving you fn(&mut Self, equalTo: T) and fn(&mut Self, T). From my perspective, this has a few problems:

  • The labels don’t necessarily make sense without the base name, and when you’re using function pointers (or function traits), you’ve got more than one possible value, with no guarantee they have the same labels. Heck, while I’ve never seen functions actually named add(to: Set<T>) and remove(from: Set<T>), surely they should have the same type!

  • If labels are part of the type system…are two different function types compatible? Can removeAll(equalTo:) be passed to a parameter of type fn(&mut Self, T)? Probably! But what about fn(&mut Self, value: T)? Is this a new implicit conversion? Can you change fn(x: f64, y: f64) to fn(y: f64, x: f64)?

  • What happens when you put fn(value: isize) into dyn Any? Can you get it out as fn(isize)? As fn(offset: isize)?

  • Putting the labels in the type undermines the user model of “these functions have different names”. (I guess this only matters if you have name-based overloading, which I’m willing to call it. I’ve got some thoughts on Python-style labels without overloading but I’m still working them out.)

Now, there is a downside of Option A too: sometimes function pointers really would benefit from labels. But those labels go with the name of the function pointer argument, not what gets passed to it. We had the idea in Swift that

fn for_each(
  &self,
  apply process: impl FnMut(key: K, value: V)
) {
  // Yes, this is inefficient, don’t worry about it.
  for k in self.keys() {
    process(key: k, value: self[k])
  }
}

would be sugar for something like

fn for_each(
  &self,
  apply process(key:value:): impl FnMut(K, V)
) {
  for k in self.keys() {
    process(key: k, value: self[k])
  }
}

but never got around to implementing it. (Still could some day, though; we left space for it.) It’s not strictly necessary, and since there are always functions without labels it’s not out-of-place or anything.

So yeah, don’t go with Option B.

5 Likes