-
-
Notifications
You must be signed in to change notification settings - Fork 0
Specification for function resolution (overloading, optional/named arguments) #3
Description
Function resolution currently uses name and arity as the signature. There are two main features that need to be worked on - overloading and optional/named arguments (which are technical two but are heavily related).
Overloading
Overloading, which is a standard quality-of-life feature for statically typed languages. The main issues with overloading are caused by overlapping types (such as Object/String), which adds complexity to resolution rules and can cause subtle bugs if the runtime behavior differs (type inference in particular can lead to the resolved function changing unexpectedly).
The current plan is to prevent/restrict overlapping types to avoid issues like this - I think most overloading only uses disjoint types or simple subtypes, so I think it makes sense to start there. Long term, other options are to require runtime behavior for overloads to be equivalent for the same values (maybe run unit tests across all possible resolutions?), and to identify when the resolved functions changes (best for dependencies).
Optional/Named Arguments
Optional arguments are useful for customizable function behavior and tend to reduce the need for overloading as well. Named arguments are almost a necessity for working with many optional arguments. However, these significantly increase the complexity of resolution - arity is no longer reliable and the order of arguments may be changed (which needs to be preserved for evaluation).
My intuition is that having a standardized concept of an options parameter works well for many use cases. This would always be the last parameter defined and would be the only optional parameter (thus allowing arity to be incorporated into the resolution strategy). For example:
func open(name: String, options: {read: Boolean = false, write: Boolean = false}): File
open("file.txt", {read = true});Incorporating a bit of syntax sugar, any named argument would implicitly be passed via options, as in open("file.txt", read = true). Atom conversions like open("file.txt", :read) would cause problems with arity, but could work if the braces are always required as in open("file.txt", {:read}).
Outside of this, it seems like the only other option is to bit the bullet and check all overloads. However, it's likely that functions with optional/named arguments wouldn't need overloads, so this becomes significantly less of an issue anyways.