-
-
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
Proposal: Defer calculation of field types until type parameters are known #18466
Comments
fwiw, there's no advantage of your complicated immutable StaticMatrix{M,N,T,L}
data::NTuple{L, T}
function StaticMatrix(d)
L == M*N || error("Type parameters don't match")
new(d)
end
end also, duplicate of #8472 |
Respectfully, I thought #8472 was much more general than this, and is about doing a fully-
That's not at all what I see. Your code executes a run-time check and my code executes a compile-time check. Run-time:
Compile-time
@vtjnash am I misinterpreting this? Perhaps the branch is eliminated in the first case (for instance, I don't see |
The only operation permissible while constructing a type is allocation (http://docs.julialang.org/en/latest/devdocs/locks/). No other inspection of the system is possible in a thread-safe manner. Additionally, you would need to provide an algorithm for allocating them uniquely during deserialization (and handling any errors), despite the fact that the system is temporarily in an inconsistent state and examining it too closely will lead to errors (e.g. you can't look at the fields of a type, since they might still contain placeholders instead). |
That seems closer to the mark. Thanks @yuyichao.
Huh? This totally confuses me. I only use I do understand the The reason I am using this "trick" is exactly because #17880 and #15369 will be fixed in the future and I am currently using Julia for real-world work now. Stating that two implementations "should" behave the same isn't really of practical value. PS - @yuyichao I'm curious - could you explain how GC frame generation in #15369 affects my |
@vtjnash Thank you very much for the insight. I totally admit that implementing this could be messy and complicated and might require changes to how the system works, and unless I can help somehow, then it remains up to you guys to figure out what is feasible, or worthwhile given the payoff. I had hoped this would be simpler than #8472 (fully-generated types) since to me as an end-user it seems pretty non-disruptive (affecting only how Thanks again. Cheers :) |
This issue is related very much to #8322, which is still open with the ideas I requested here. |
No. The point is not how reproducible it is across systems but how easy it is to understand the difference. For 99% of the case (the 1% being codegen/llvm bugs)
The better workaround is to move the condition in a
|
Yes llvm is usually easier to read, though I have noticed some operations in I think its just unusual that most the code in StaticArrays is extremely simple (e.g. adding two pairs of floats, or the (shorter) constructor above) so I found both formats readable and I used a combination of both. But thank you for the advice - I'll err toward llvm from now on.
Agreed (there was a comment in my codeblock about that, but you had to scroll sideways... the given version is 0.4 friendly). Right, awesome, thank you! I'm glad for that optimization... previously I was really pessimistic about throwing errors in StaticArrays since code is so performance sensitive but I see all this will work out beautifully in the end. |
99% of the time not in any way you would care about.
Those are llvm instrinsics (i.e. instructions) and are never function calls to begin with. |
Exception being #16375 |
OK, thanks for all the useful info @yuyichao! I'll read up on the intrinsics, and then I should be good to use (On a side note, |
#8322 asked for two features, one the same as this issue and one for computed subtyping. I believe those have very different implications, so we should have separate issues for them. I do think it is possible to support this by storing functions to compute the field types (based on a syntactic heuristic, e.g. a type parameter occurs somewhere other than inside a type application |
Thanks guys.
Agreed. |
Fair enough. If we prohibit types with generated fields from being isbits (e.g. guarantee they will be heap allocated) that should likely help with making the layout and precompile serialization computable (and not cause #18343, #16767, & friends to be reopened). |
Do you mean just the abstract types? For the concrete types, isbits would be crucial in some circumstances, especially for the |
I needed this desperately so I've written an intermediate solution that uses macros and does allow correct type inference. Its still a prototype and a bit hacky, but it works :-). I guess one would implement this differently if one wants to add language support, but I hope its useful to everyone that is waiting for this feature. |
Nice. |
there seems to be some weird, non-hygienic |
I didn't want to eval Here is an example to illustrate where
In general using eval here is not bulletproof for sure. If one has a Another nice side effect of using PS: Further discussion should be probably be made in the issue tracker of the package. |
Right, yes, I completely understand both - your package seems very useful, complete and simple. I really like it! Nonetheless, I would be using My speculation was about how to remove |
The trouble with |
I think you might have misunderstood my suggestion. I was saying that if you apply a type variable to a type, and that type then has all non-hidden parameters filled, then the hidden parameters will be calculated always and automatically. So going back to the supposed semicolon notation, if I had |
I'm not misunderstanding, I'm just pointing out that wrapping this in different syntax has no actual impact on what is possible for the underlying implementation. In order to fill in the extra parameters, you need an eval stage. In my example package, that eval stage is called |
I've been pondering using StaticArrays in ACME for quite a while. And I think it would be a perfect fit, if it wasn't for the proliferation of type parameters. It's based on state-space models, which (in the linear case) operate as x(n) = Ax(n-1) + Bu(n) That would translate to (fixing the eltype for simplicity): struct StateSpaceSystem{Nx,Nu,Ny,NxNx,NxNu,NyNx,NyNu}
A::SMatrix{Nx,Nx,Float64,NxNx}
B::SMatrix{Nx,Nu,Float64,NxNu}
C::SMatrix{Ny,Nx,Float64,NyNx}
D::SMatrix{Ny,Nu,Float64,NyNu}
end Bad enough. But actually, I'm simulating non-linear systems, which I incorporate by using even more matrices (with interdependent sizes, of course). Also, I'm very concerned about speed (why else spend the effort of changing to StaticArrays), so I really want all types concrete to avoid dynamic dispatch. Is there some best practice how to cope with the situation? |
struct StateSpaceSystem{Nx, Nu, Ny,
AT <: SMatrix{Nx, Ny},
BT <: SMatrix{Nx, Nu},
CT <: SMatrix{Ny, Nx},
DT <: SMatrix{Ny, Nu}}
A::AT
B::BT
C::CT
D::DT
end Or you could use https://github.com/vtjnash/ComputedFieldTypes.jl to achieve the exact same result as proposed in this issue, although I think the proposal in this issue may be more cumbersome than using the above (although it does provide an implementation of
If you don't like using |
* origin/master: (22 commits) separate `isbitstype(::Type)` from `isbits` (#26850) bugfix for regex matches ending with non-ASCII (#26831) [NewOptimizer] track inbounds state as a per-statement flag change default LOAD_PATH and DEPOT_PATH (#26804, fix #25709) Change url scheme to https (#26835) [NewOptimizer] inlining: Refactor todo object inference: enable CodeInfo method_for_inference_limit_heuristics support (#26822) [NewOptimizer] Fix _apply elision (#26821) add test case from issue #26607, cfunction with no args (#26838) add `do` in front-end deparser. fixes #17781 (#26840) Preserve CallInst metadata in LateLowerGCFrame pass. Improve differences from R documentation (#26810) reserve syntax that could be used for computed field types (#18466) (#26816) Add support for Atomic{Bool} (Fix #26542). (#26597) Remove argument restriction on dims2string and inds2string (#26799) (#26817) remove some unnecessary `eltype` methods (#26791) optimize: ensure merge_value_ssa doesn't drop PiNodes inference: improve tmerge for Conditional and Const ensure more iterators stay type-stable code loading docs (#26787) ...
* origin/master: (23 commits) fix deprecations of \cdot and \times (#26884) Support reshaping custom 0-dimensional arrays (#26870) fix some cases of dot syntax lowering (#26878) Pkg3: deterministically close the LibGit2 repo in tests (#26883) code loading docs: add missing graph edge (#26874) add news for #26858 and #26859 [ci skip] (#26869) Deprecate using && and || within at-dot expressions (#26792) widen `Int8` and `Int16` to `Int` instead of `Int32` (#26859) fix #26038, make `isequal` consistent with `hash` for `Ptr` (#26858) Deprecate variadic size(A, dim1, dim2, dims...) method (#26862) add using Random to example in manual (#26864) warn once instead of depwarn since we want to test it Revert "reserve syntax that could be used for computed field types (#18466) (#26816)" (#26857) Fix compilation on LLVM 6.0 change promotion behaviour of `cumsum` and `cumsum!` to match `sum` [LLVM 6] add patch to diamond if-conversion add a precompile command that can be used to precompile all dependencies (#254) use registry if no version entry exist in project for developed pacakges make Pkg3 work as a drop in for the old CI scripts update registries when adding (#253) ...
`MMatrix{3,3,L}` is not a concrete type, unfortunately. I figured I'd suggest changing this so inference of `getfield(::Cell, :lattice)` isn't poisoned. The same problem affects the `positions` but it cannot be fixed simply while retaining the `MMatrix` approach cf. JuliaLang/julia#18466: personally, I think it'd make more sense to treat that as a `Vector{MVector{3,P}}` - it doesn't seem worthwhile to specialize to how many atoms are in a cell. Anyway, that is a larger change and I just wanted to do the minimal change here.
I know there is some debate about this, but marking as a duplicate of #8472 to consolidate discussion there. |
Currently, we can perform a limited set of logic in the type definition, such as:
but we can't involve a type parameter, such as:
AFAICT, at the moment the field types
A.types
is calculated when the type is defined and type parameters are inserted into the correct slots as they become known.However, it would be nice if the types could be calculated by arbitrary inferrable or
@pure
functions. Another simple example (close to my heart) would be:However this results in an error that multiplication is not defined for
TypeVar
s. Instead, I need all of this code:and my users need to foist around the redundant
L
paramater when they need to specify a concrete type.For abstract types, I'm hoping that inference itself could still be used to come up with a least-pessimistic approximation of each field, or otherwise just use
Any
when that's not possible. If that makes it difficult to avoid regressions, straight types (combinations of types and the relevantTypeVar
s withapply_type
but no other functions) could keep functioning as they currently do.The text was updated successfully, but these errors were encountered: