Skip to content
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

Defining a Foo{T} constructor for Foo{T, S <: T} #39280

Closed
CameronBieganek opened this issue Jan 16, 2021 · 1 comment · Fixed by #51979
Closed

Defining a Foo{T} constructor for Foo{T, S <: T} #39280

CameronBieganek opened this issue Jan 16, 2021 · 1 comment · Fixed by #51979
Assignees
Labels
bug Indicates an unexpected problem or unintended behavior docs This change adds or pertains to documentation types and dispatch Types, subtyping and method dispatch

Comments

@CameronBieganek
Copy link
Contributor

The manual doesn't provide a definition for what it means to define a constructor for a parametric type where the number of type parameters accepted by the constructor is fewer than the number of type parameters for the type. In simple cases, it works as expected, but for more complicated cases, the lack of a formal semantics leads to mass confusion, as demonstrated by this Discourse thread.

From that thread, we came up with the following MWE.

This works:

julia> struct Bar{T, S} end

julia> Bar{T}() where {T} = T

julia> Bar{Integer}()
Integer

But this does not:

julia> struct Foo{T, S <: T} end

julia> Foo{T}() where {T} = T

julia> Foo{Integer}()
ERROR: UndefVarError: T not defined
Stacktrace:
 [1] Foo{Integer,S} where S<:Integer() at ./REPL[2]:1
 [2] top-level scope at REPL[3]:1

Without a definition of what it means to define Foo{T}() where {T} = # ... it's difficult to know if this is a bug or if this is expected behavior. And if it is the expected behavior, it would be nice to know what the semantic rule is that explains this behavior (and it would be nice to have that explanation in the manual).

@CameronBieganek CameronBieganek changed the title Defining a Foo{T} constructor for struct Foo{T, S <: T} end Defining a Foo{T} constructor for Foo{T, S <: T} Jan 16, 2021
@JeffBezanson JeffBezanson added docs This change adds or pertains to documentation types and dispatch Types, subtyping and method dispatch labels Jan 19, 2021
@JeffBezanson
Copy link
Member

It helps here to understand that two different processes are happening: (1) picking a method to call, and (2) once inside the method, determining the value of T (#39277 has a similar concern). (1) is based entirely on subtyping. The signature of the method is

Tuple{Type{Foo{T}}} where T

(The type the method is defined on just gets wrapped in Type{ }.)

Tuple{Type{Foo{Integer}}} is indeed a subtype, so the method matches. However determining T is a hard problem. For example currently we have

julia> intersection_env(Type{Foo{Integer}}, Type{Foo{T}} where T)
svec(Type{Foo{Integer, S} where S<:Integer}, svec(T<:(Union{Integer, S} where S<:Integer)))

so we think we don't know the value of T for sure, but we actually could. So it's basically a bug, but it's more that we need to improve the algorithm used to infer static parameter values.

@JeffBezanson JeffBezanson added the bug Indicates an unexpected problem or unintended behavior label Jan 19, 2021
@JeffBezanson JeffBezanson self-assigned this Jan 19, 2021
vtjnash added a commit that referenced this issue Oct 31, 2023
Record the 'scope' of the variable that was undefined (the Module, or a
descriptive word such as :local or :static_parameter). Add that scope to
the error message, and expand the hint suggestions added by the REPL to
include more specific advice on common mistakes:

  - forgetting to set an initial value
  - forgetting to import a global
  - creating a local of the same name as a global
  - not matching a static parameter in a signature subtype

Fixes #17062 (although more could probably be done to search for typos using REPL.string_distance and getting the method from stacktrace)
Fixes #18877
Fixes #25263
Fixes #35126
Fixes #39280
Fixes #41728
Fixes #48731
Fixes #49917
Fixes #50369
vtjnash added a commit that referenced this issue Nov 8, 2023
Record the 'scope' of the variable that was undefined (the Module, or a
descriptive word such as :local or :static_parameter). Add that scope to
the error message, and expand the hint suggestions added by the REPL to
include more specific advice on common mistakes:

  - forgetting to set an initial value
  - forgetting to import a global
  - creating a local of the same name as a global
  - not matching a static parameter in a signature subtype

Fixes #17062 (although more could probably be done to search for typos using REPL.string_distance and getting the method from stacktrace)
Fixes #18877
Fixes #25263
Fixes #35126
Fixes #39280
Fixes #41728
Fixes #48731
Fixes #49917
Fixes #50369
@vtjnash vtjnash closed this as completed in 449c7a2 Nov 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior docs This change adds or pertains to documentation types and dispatch Types, subtyping and method dispatch
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants