-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
WIP static dispatch for kwargs and structural fields #16580
Conversation
Very interesting. Having a nicer approach to keyword args, with covariant records, definitely seems important for the language. (Prior art includes e.g. NamedTuples.jl) |
4a169cb
to
2aec001
Compare
This is passing tests. |
As for all the typesystem issues, it'll probably need a healthy dose of discussion. In the meantime, if this approach is not too flawed it can probably just be used internally for keyword args. |
How does this compare with |
The main difference is that the ImmutableDict is not specialized on the set of keys it holds. I'm not sure but I'd assume that it's a little overkill for something like the printing system where the lookup of the printing options is probably negligible compared to the stuff you're doing there. |
Yeah, but if all keyword arguments are collected that way, there would be little point in opting out of that optimization, at the cost of a slightly non-standard syntax. |
You could, but IOContext and Struct should have roughly the same runtime performance. But IOContext also should have no compile-time or dispatch costs since it doesn't require any code specialization to achieve that performance, whereas those costs for Structs could be quite high. I agree this is very interesting, although it has some minor implementation items to fix (methods in Core shouldn't be extended, meaning this should be a TopModule feature, not a CoreModule). I would also like to see some examples where this hits worst-case behaviors and what metrics we can apply to limit those. Maybe that would be something like |
I think the trade-off is more complex than that since for IOContext you don't get type information out of the dict right ? I agree that in a lot of cases the compilation overhead will trump whatever you're winning from that (and I think it's definitely the case for the IO stuff). I'm also quite curious on what a torture test will look like for that, although to be fair we already have similar problems with large tuple arg splatting in a couple places. I'll try to have a look this week (but anyway we can discuss that in person too since I'm landing @ stata friday afternoon :-) ) |
Worth pointing out that in the current scheme, kwargs are converted to positional args, after which we still specialize on the types of all of them. Eventually we might want to do stuff like using the kwarg type partially, to do static dispatch but not specialize on every case (static dispatch to partially-specialized code). It will be much more work, but it would be great to eventually eliminate the separate "kwfunc" by putting tuple and struct signatures in the same method table.
Yay! |
How is this going? I'm really interested in the improvements here, not just to be able to dispatch on kwargs, but the |
Is this still on track for v0.6?
Plots.jl and DifferentialEquations.jl make heavy use of keyword arguments and I would be happy to do some tests. Gadfly is another case too. Optim.jl used to, but it did a re-design with an options type to get around this problem. |
I had a slightly crazy idea along these lines the other day. We could add the ability to annotate elements of a Tuple type with names, like so:
syntax for an instance: possible syntax for the type: A tuple with this type would behave exactly like a
Unfortunately this doesn't seem to serve up a solution for keyword arguments on a silver platter; subsetting keyword args is still a problem, and the fact that this type is inherently ordered doesn't seem to help either. But it could be an interesting design to consider. |
I really like the idea that both "normal" tuples and named tuples are the same type. I still have the problem that I would very much want the named tuple syntax to infer names of members, if possible. E.g. if Btw., have you seen the object spread feature in TypeScript 2.1? I think that would be another fantastic syntax to have with named tuples. |
@JeffBezanson would there be any hope in allowing E.g. here's something that would be quite useful (combined with an invented use of immutable Table{Cols <: Vararg{Named}} # Maybe `Cols...` would be short for this?
Cols...
end So long as one could iterate over the fields in some way (e.g. in a recursive, "lispy-like" way, like we do for tuple), then we would have a useful
For the language, I kind-of prefer the latter (but with |
Looking this over again, it looks pretty good and I'll probably try to revive this for 1.0. The needed changes are:
|
Very cool! Is the plan to implement #1974 and then introduce a type like
where I also assume that as a first step this would just introduce the type, and any syntactic sugar for constructing named tuples would come later? |
This would have to include syntactic sugar, naturally! :) Actually I think it's pretty important to add the |
#22194 supercedes this, so we don't need to keep this open or on the 1.0 milestone anymore. |
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
I tried a couple approaches for kwargs but this one I like.
It introduces a structural named-fields counterpart to tuple types (unimaginatively called
Struct
). You can make aStruct(x = 1.0, y = 2.0)
and it has typeStruct{(:x,:y),Tuple{Float,Float}}
with fieldsx
andy
.There is a couple functions to merge or diff them and it uses that as the basis for kwargs splatting and unpacking.
This PR is not ready yet and is up here mostly to discuss the implications. The problematic one are probably over-specialization and the use of staged functions in the implementation (as always).
Assuming we want this, here are a few points I'm wondering about :
Tuple
so that we have only one kind of structural type. We'd get dispatch-on-kwargs for "free" (== retrofit all code that touches tuple types ... hem). This is probably a long term question and keeping them separate is a decent first step in that direction anyway.{x::Int, y?::Int}
that has{x::Int,y::Int}
and{x::Int}
as subtypes. I tink this is necessary if we want to express our current kwarg semantics using only normal dispatch and avoid generating a lot of methods.Struct
types take ordering into account but the kwarg lowering/merging/diffing always keeps them sorted to avoid generating a specialization for every permutation.Other than that, it currently seem to work when used as a replacement for our current kwarg lowering and we get specialization, inlining, inference etc.
Going forward with this we can probably remove a bit of the
kwfunc
business but for now I only did minimal integration.I feel that the
Struct
type is interesting in itself anyway.