<div dir="ltr"><div><div><div>Hi All,<br><br></div><div><div><div><div><div><div><div><div><div> So we had a bunch of useful discussion about what we wanted to support in functions. There was a pretty clear decision to only support overloading for library functions at this stage, but I think a few things were left unspecified, since there are a lot of potential variations. <br><br><br></div>To pin it down, I'm going to attempt to define some terms and precisely talk about what design decision we're making.<br><br></div><div>Definitions<br>========<br></div><div><br></div><div>Function definition: a single function definition that specifies the types and names of arguments, plus info for any additional features about arguments<br></div><div>Composite functions: functions with a Swift body<br></div><div>Function callsite: a place in the program where the function is called with a list of arguments. In general, we can have f(1, 2, 3, argname1=4, argname2=5)<br>Overloaded function definitions (Overloads): where multiple function definitions with the same name exist, and they are disambiguated at the function callsite based on the callsite arguments<br></div><div><br></div><div>Callsite argument categories:<br></div>Positional Arguments (PosArgs) - when the the caller only specifies position. e.g. f(1,2,3)<br></div></div><div>Keyword Arguments (KWArgs) - when the callsite specifies the name of the argument, e.g. f(x=1, y=2). This allows them to be specified out of order or with some omitted<br><br></div><div>Function definition argument categories:<br></div><div>Required Arguments(ReqArgs) - arguments that are required<br></div><div>Variadic Arguments (VarArgs) - the last argument in the function definition can match 0 or more PosArgs<br>Optional Arguments (OptArgs) - when a default value is provided for an argument, e.g. f(arg=2)<br></div><div>Polymorphic Arguments (PolyArgs) - when a argument in the function definition can be one of set of types (e.g. wildcard type, type variables, union types)<br></div><div><br></div><div>Matching rules (I've marked the ones up for discussion with a ??? and uncontroversial ones with :)):<br></div><div>PosArgs -> ReqArgs - :)<br></div><div>PosArgs -> VarArgs - :)<br>PosArgs -> OptArgs - ???<br></div><div>KWArgs -> ReqArgs - ???<br>KWArgs -> VarArgs - ???<br></div><div>KWArgs -> OptArgs - :)</div><div><br></div><div>Restrictions<br>=========<br></div>Overall restrictions that I think we agree on, for now:<br></div>* VarArgs and OptArgs cannot be used in same function definition.<br></div><div>* Any OptArgs must be followed only by other OptArgs<br></div>* VarArgs cannot be used in composite function definitions<br></div>* PolyArgs cannot be used in composite function definitions<br><br></div>So now I think there are a few somewhat different ways we can allow the other features to be combined. The baseline features, that I will assume for the rest are:<br><br></div><div> ReqArgs + PosArgs. + VarArgs + (PosArgs -> ReqArgs) + (PosArgs -> VarArgs)<br></div><div><br>My understanding of the current states of Swift/T and Swift/K are:<br><br></div><div> T -VarArgs|OptArgs + PolyArgs<br></div><div> K -VarArgs|OptArgs + PolyArgs (sorta) + KWArgs + (KWArgs -> OptArgs)<br></div><div><br>If we want to extend things, first, this would be the attempt to support everything in combination.<br><br></div> PolyArgs + VarArgs|OptArgs + KWArgs +(PosArgs -> OptArgs) + (KWArgs -> ReqArgs) + (KWArgs -> VarArgs) + Overloading<br><br></div>I think we agree that this is not reasonable to implement. I'm not totally clear on which subset we are planning to support though. One restriction that seems reasonable is to disallow the combination of PolyArgs and Overloading:<br><br> VarArgs|OptArgs + PolyArgs|Overloading + KWArgs +(PosArgs -> OptArgs) + (KWArgs -> ReqArgs) + (KWArgs -> VarArgs)<br><br>Maybe we also don't really need (KWArgs -> ReqArgs) + (KWArgs -> VarArgs) - they seem marginally useful at best. I think it's also reasonable to restrict matching so that KWArgs are always matched before PosArgs. I.e. f(1, x=1) doesn't match f(int x=0, int y=0) . I'll call this KWArgsBeforeOptArgs. This corresponds to the algorithm "Match n positionals with first n args, then resolve KWArgs to remaining OptArgs"<br><br>That would leave:<br><br> VarArgs|OptArgs + PolyArgs|Overloading + KWArgs +(PosArgs -> OptArgs) - KWArgsBeforeOptArgs<br><br></div><div>I think resolving overloads here is still a little complex because we need to consider multiple ways to match keyword arguments to positional arguments. It's also difficult to work out (in the compiler or in the programmer's head) if two overloaded definitions may potentially conflict because the matching of callsite args to definition arguments is complex. I think the possibility exists if the ReqArgs of one overload is a prefix of the ReqArgs of the another overload and there's some overlap in keyword arg names. I'd imagine in many situations where people might want to use OptArgs+Overloading, then this is a possibility.<br></div><div><br></div><div>One option (I think Swift/K does this) is to strictly match PosArgs to ReqArgs and KWArgs to OptArgs. <br><br> VarArgs|OptArgs + PolyArgs|Overloading + KWArgs<br></div><div><br>I think it is probably not too difficult to resolve overloads with KWArgs in this situation. The restriction {positionals1} = {positionals2} or
{keywords1} ∩ {keywords2} != 0 that Mihael proposed on overloading does help things here. I still find this choice a little unsatisfying because programmers often would prefer to provide optional arguments positionally. <br><br>Another option is to discards KWArgs, leaving us:<br><br> VarArgs|Optargs + PolyArgs|Overloading + (PosArgs -> OptArgs) - KWArgsBeforeOptArgs</div><div><br></div><div>I think we agree that KWArgs are a nice feature that we'd like to have, so that's not great either. Maybe we can disallow OptArgs for overloads though - it seems like in most situations you would use one or the other, not both. We could potentially <br></div><div>This would give us:<br></div><div><br> VarArgs|OptArgs + PolyArgs + KWArgs +(PosArgs -> OptArgs) - KWArgsBeforeOptArgs<br> VarArgs + PolyArgs|Overloading + KWArgs +(PosArgs -> OptArgs) - KWArgsBeforeOptArgs<br><br></div><div><br></div></div>