Skip to content

replace constructorof with something not UB #99

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

vtjnash
Copy link

@vtjnash vtjnash commented Mar 14, 2025

It is confusing that constructorof is documented as returning the constructor of T, which is normally defined to be T, and then typically does not return T, and so does not usually construct T. However, this PR is intended just to remove the undefined behavior here of using an unsound generated function (examining mutable state with getfield).

It is confusing that `constructorof` is documented as returning the constructor of `T`, which is normally defined to be `T`, and then typically does not return `T`, and so does not usually construct `T`. However, this PR is intended just to remove the undefined behavior here of using an unsound generated function (examining mutable state with getfield).
@rafaqz
Copy link
Member

rafaqz commented Mar 14, 2025

This didn't work out so well in the past:

#55

It would need to come with an assurance that its type stable and new julia versions wont break that. constructorof being type unstable has consequences for a lot of packages.

(constructorof doesn't necessarily return the constructor of T... but some function that will construct an object of T from the properties (usually modified somehow) of another constructed T. Which is often T. But often there is no actual constructor defined that does that, or extra type parameters are needed)

@KristofferC
Copy link
Contributor

There is also UB at

T = getfield(parentmodule(F), nameof(F))
.

@vtjnash
Copy link
Author

vtjnash commented Mar 14, 2025

#55 does not appear to have anything at all to do with this, except for pattern matching on the text "generated", as that touches a different function for different reasons

@KristofferC that is good to know too. That one may be harder to make entirely safe, since it exists for the specific purpose of violating the safety of the compiler, but can perhaps have the same change made to it anyways

@rafaqz
Copy link
Member

rafaqz commented Mar 15, 2025

#55 just has the "removing generated function lead to type instability and bug reports" problem.

This generated function was also for performance at some stage - but that may have been driven by wanting to avoid .wrapper internals.

@vtjnash it would just be good to have confirmation that Base.typename(T).wrapper is always type stable.

getfield(parentmodule(T), nameof(T))
end

constructorof(T::Type) = Base.typename(T).wrapper
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
constructorof(T::Type) = Base.typename(T).wrapper
constructorof(::Type{T}) where T = Base.typename(T).wrapper

Is there a reason why the where T was dropped as well?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, the where just reduces the information inference is permitted to use about the argument during inlining

Copy link
Member

@rafaqz rafaqz Mar 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I guess I don't understand the scope of consequences of that.

From practical experience using where on types and functions like this often fixes type stability bugs.

(The reason for my concern is a small loss of type stability in constructorof could break the performance of 100s of packages)

@aplavin aplavin mentioned this pull request Mar 15, 2025
@aplavin
Copy link
Member

aplavin commented Mar 15, 2025

Could you please rebase on master? CI was cleaned up there to avoid almost all spurious test failures.

@vtjnash
Copy link
Author

vtjnash commented Mar 15, 2025

It appears that you have that ability disabled in settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants