Skip to content

Conversation

SeSodesa
Copy link
Contributor

@SeSodesa SeSodesa commented Aug 29, 2025

This is to resolve errors with including units into FiniteDifferences.jl. See JuliaDiff/FiniteDifferences.jl#244 for details.

Tests for Units.jl need to be updated (the @test_throws ones), if this is to be accepted. The totalness of unit introduced via unit(::Any) might be a bit controversial, but I don't think that should be a problem. In general, things don't have units. Only (some) Numbers do.

Closes #806.

…it(::Type{Union{Missing,T}})

This is to resolve errors with uncluding units into FiniteDifferences.jl.
See JuliaDiff/FiniteDifferences.jl#244 for details.

Tests for Units.jl need to be updated, if this is to be accepted.
The totalness of unit introduced via unit(::Ay) might be a bit controversial,
but I don't think that should be a problem. In general, things don't have units.
Only Numbers do.

Closes JuliaPhysics#806.
@SeSodesa SeSodesa marked this pull request as draft August 29, 2025 09:22
@SeSodesa SeSodesa changed the title Define unit(::Any)m unit(::Funciton) and add a type restriction to unit(::Type{Union{Missing,T}}) Define unit(::Any), unit(::Function) and add a type restriction to unit(::Type{Union{Missing,T}}) Aug 29, 2025
@SeSodesa
Copy link
Contributor Author

SeSodesa commented Aug 29, 2025

Looks like there are not too many tests failing because if this change, but there are apparently things like dates that should be throwing because of some reason that I still need to decipher. Any comments on this would be appreciated.

@SeSodesa
Copy link
Contributor Author

Ah, right, the methods were intentionally missing for date-type units where a duration cannot be fixed sensibly. I'll need to modify this a bit to keep those semantics intact.

…e types with ambiguous units

For example, Years are not always the same length, so they do not have
unambiguous units. Many abstract Date types also do not have units.
Copy link

codecov bot commented Aug 30, 2025

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (master@c1a9b4e). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/utils.jl 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             master     #807   +/-   ##
=========================================
  Coverage          ?   89.46%           
=========================================
  Files             ?       21           
  Lines             ?     1699           
  Branches          ?        0           
=========================================
  Hits              ?     1520           
  Misses            ?      179           
  Partials          ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@SeSodesa SeSodesa marked this pull request as ready for review August 30, 2025 11:56
Copy link
Collaborator

@sostock sostock left a comment

Choose a reason for hiding this comment

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

Restricting T in the method unit(::Type{Union{Missing, T}}) is the correct thing to do to fix the stack overflow. Adding unit(::Any) and unit(::Function) is not.

SeSodesa and others added 2 commits September 1, 2025 13:48
As suggested by @sostock, do not only restrict the type of T to Number, but include FixedPeriod as well, to accommodate Dates-soecific code.

Co-authored-by: Sebastian Stock <[email protected]>
…:Type{Union{Missing, T}}) and remove unwanted unit methods

Now the tests run again. Still need to revert the tests that were
converted from throwing  MethodError to outputting NoUnits.
@SeSodesa SeSodesa force-pushed the make-unit-function-total branch from 8712763 to c230a6a Compare September 1, 2025 11:02
…ng against NoUnits

This was to accommodate the removed unwanted methods unit(::Any) and
unit(::Function).
@SeSodesa SeSodesa changed the title Define unit(::Any), unit(::Function) and add a type restriction to unit(::Type{Union{Missing,T}}) Prevent infinite recursion of unit by adding a type restriction to unit(::Type{Union{Missing,T}}) Sep 1, 2025
@SeSodesa
Copy link
Contributor Author

SeSodesa commented Sep 1, 2025

I changed the title of the pull request to reflect its scope. I will look into why FiniteDifferences.jl does what it does more deeply. At the very least I am currently trying to take the unit of a function being differentiated in JuliaDiff/FiniteDifferences.jl#244. A quick look indicates that estimate_step might allow both containers and functions as input, so allowing unit(::Any) with unit(eltype(f)) made it seem like it functioned as intended.

@SeSodesa
Copy link
Contributor Author

SeSodesa commented Sep 1, 2025

And eltype of T<:Function is any.

@sostock
Copy link
Collaborator

sostock commented Sep 1, 2025

After thinking some more about this, I’m not sure this is necessary.

The stack overflow only happens when someone calls unit(Any). With this PR, unit(Any) throws a MethodError instead of a StackOverflowError. So it only changes what kind of error is thrown.

Before this PR, a user could define unit(::Type{MyType}) any would get a working unit(::Type{Missing, MyType}) via this method. After this PR, this is only the case if MyType <: Union{Number, Dates.FixedPeriod}. Therefore, this could actually be considered breaking. However, I don’t think it is likely that someone defines unit on a type that is not <: Number, so this may not matter.

@SeSodesa
Copy link
Contributor Author

SeSodesa commented Sep 1, 2025

The different kind of error might be a good thing, though. It could function as an explicit way of telling a user that they misimplemented something, which is what I did and spent some time tracking down what and why, especially since the purpose of each method is not documented.

The method unit(::Any) could throw a specific error with a more informative error message, such as

function unit(x::Any)

    NotImplementedError("You tried calling unit on an object $x, that has none defined. Not everything has (or should have) units.")

end

User experience, and all that. StackOverflowErrors are never very nice.

@SeSodesa
Copy link
Contributor Author

SeSodesa commented Sep 1, 2025

Then the type restriction could be lifted to allow defining unit on type other than T <: Number.

This allows us to remove the type restriction on T for
unit(::Type{Union{Missing,T}}), making it possible for users to
define unit on their own types, while at the same time giving a more
descriptive error message than StackOverflowError.
SeSodesa and others added 3 commits September 3, 2025 21:19
…e{Union{Missing,T}})


Not needed after re-removal of type constraint.

Co-authored-by: Sebastian Stock <[email protected]>
…urposes

Also changed the exception type thrown by unit(::Type{Any}) to ArgumentError,
and changed the error description to be more helpful.
@SeSodesa SeSodesa force-pushed the make-unit-function-total branch from 3d2e362 to 108bc4e Compare September 3, 2025 18:39
@SeSodesa
Copy link
Contributor Author

SeSodesa commented Sep 3, 2025

Had to force push to amend a commit message. But maybe this is close to completion now.

@SeSodesa SeSodesa changed the title Prevent infinite recursion of unit by adding a type restriction to unit(::Type{Union{Missing,T}}) Prevent infinite recursion of unit by adding a method unit(::Type{Any}) Sep 3, 2025
SeSodesa and others added 2 commits September 5, 2025 15:57
The docstring is not needed, as this is not a feature that users need to
know about in the documentation.
…ssage


Line break escaping not supported in multi-line strings in older Julia versions.

Co-authored-by: Sebastian Stock <[email protected]>
Copy link
Collaborator

@sostock sostock left a comment

Choose a reason for hiding this comment

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

Just two small comments to make the code style consistent with the rest of the package. Then this is ready to merge.

SeSodesa and others added 2 commits September 15, 2025 11:05
No empty lines between comments and code, and no spaces after opening parentheses of function invocations.

Co-authored-by: Sebastian Stock <[email protected]>
Remove space between closing parentheses of nested function invocations

Co-authored-by: Sebastian Stock <[email protected]>
@sostock sostock merged commit d14ad5b into JuliaPhysics:master Sep 15, 2025
15 checks passed
@sostock
Copy link
Collaborator

sostock commented Sep 15, 2025

Thanks!

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.

The method unit(x::Type{Union{Missing,T}}) is causing stack overflow
2 participants