-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide way for a function to use the contextually expected type as its return type #386
Comments
#426 can now do this. |
We will make #426 just cover the return type coming from a typedesc parameter. Then we can cover defaulting the typedesc parameter to the contextually expected type here. |
This builds on #426 by allowed the parameter to be defaulted using the following syntax: function query(string q, typedesc rowType = <>) returns stream<rowType, sql:Error> = external; The It's not quite as simple as using the contextually expected type. Consider stream<Customer,sql:Error> stm = client->query(“SELECT ...”); In this case, we want to default the rowType parameter to Customer. So the contextually expected type gives the return type and from this return type we determine the default for the rowType. This needs the rework of contextually expected type from #392. |
I think we can deal with this independently of #392. What we need to do is a simple form of unification. Suppose we have a declaration of a function f with parameter t of type typedesc<T> and with return type R, which refers to t. Now suppose we have a call to f, with a contextually expected type of C and with no argument specified for t. What we need to do is unify C and R, where we treat R as having t as a variable. We will use the notation R{ t -> X } to mean the result of substituting X for t in R. Then what we need to do is find a type descriptor S such that R{ t -> S} is equivalent to C, where S must be a subtype of T. We then call f with a typedesc value representing S as the value for t. In the above case, our function will be declared as:
and we have a call:
So in this case. we are unifying stream<rowType, sql:Error> and stream<Customer,sql:Error> treating rowType as a variable, constrained to be a subtype of record{}. This is a super simple kind of unification. To unify these two, we recursively unify rowType with Customer, which we can do with a substitution of { rowType -> Customer }, and sql:Error with sql:Error, which succeeds without any substitutions. Thus the result of the unification is a substitution { rowType -> Customer }. We check that Customer is a subtype of record {}. Then we call call the |
A couple of questions:
function getValue(typedesc<anydata> td = <>) returns Person|td = external;
// usage
Employee|Student|map<string> val = getValue();
function getTuple(typedesc<int|string> td1 = <>, typedesc<record {}> td2 = <>, typedesc<float|boolean> td3 = <>) returns [td1, td2, td3] = external;
// usage
[int, Person, float] tup = getTuple(); |
On point 1, I think we need to support:
Similarly for error. So if we are trying to infer t and we have a type T|t, I would suggest we require that the possible basic types for T and t are disjoint (e.g. in this case nil and mapping). (We do something similar with the applicable contextually expected type already.) On point 2, I think it makes sense but I can't think of a case where we need it. If it's no extra work to implement, then go for it, otherwise I wouldn't bother at this point. WDYT? |
IIUC, then the type inferred for function getValue(typedesc<any|error> t = <>) returns t|E1|E2 = external;
// usage
Foo|Bar|error val = getValue(); Then, the type inferred for function getValue(typedesc<any|error> t = <>) returns t|error = external;
// usage
Foo|Bar|E1|E2 val = getValue(); And regarding the support for multiple inferences, it's already supported in the current implementation I'm working on since it was straight forward with the work done for #426. But for unions, with the above complications, I think we'll have to allow just one inference. |
@pubudu91 Sorry I didn't reply earlier. I allowed only one Your 2nd example isn't right because I cannot assign In your first example, I would expect t to be inferred as
then T and R should have disjoint basic types. So this:
wouldn't be allowed (assuming E1 and E2 are subtypes of error), but this would:
Does that make sense? |
Ah yes, that makes sense. Thanks! Misunderstood what you said about disjoint sets earlier. |
There are several place where a function needs to "data bind" its result. Two examples:
We do the 1st one currently in a rather hacky way:
(I'm ignoring some type checking rules here - that line does not compile.)
What we need is a way to say that the return type is the contextually expected type and to pass that typedesc into the function as a parameter so the code can try to return that. If there's a possibility that it might not be able to then the programmer can union the return type with error or possibly even panic.
Current http:get is as follows:
What I want is something like this:
Then, I can just use it like this:
This is using the @typeparam thing we're using in LangLib as a poor man's parametric typing system. (I'm probably not using it properly.)
[Summarized from an email discussion with James.]
The text was updated successfully, but these errors were encountered: