# Parametric inner constructor inherits parameter from global scope

**URL:** https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296
**Category:** Internals & Design
**Tags:** question
**Created:** [March 25, 2019, 11:17am UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296 "2019-03-25T11:17:21Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)
#### Post date: [March 25, 2019, 11:17am UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/1 "2019-03-25T11:17:22Z")

</div>

See [Parametric composite type inner constructors in Julia: Why is `where {T}` necessary? - Stack Overflow](https://stackoverflow.com/questions/55335832/parametric-composite-type-inner-constructors-in-julia-why-is-where-t-necess/55336481) for the original question.

Now parametric inner constructor without `where` inherits its parameter from global scope if it is defined. I wanted to make sure that it is an intended behavior (the reason I ask is that it can lead to surprising bugs that structure definition depends on global scope).

Here is an example:

```julia
julia> T = String
String

julia> struct Point{T}
           x::T
           y::T
           Point{T}(x,y) = new(x,y)
       end

julia> Point{String}("b","a")
Point{String}("b", "a")

julia> Point{String}(SubString("b",1,1),SubString("a",1,1))
Point{String}("b", "a")

julia> Point{Int}(1, 2)
ERROR: MethodError: no method matching Point{Int64}(::Int64, ::Int64)

julia> Point{String}(1, 2)
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String

```

We have a similar behavior also for “normal” functions:

```julia
julia> T
String

julia> f(x::T, y::T) = x*y
f (generic function with 1 method)

julia> methods(f)
# 1 method for generic function "f":
[1] f(x::String, y::String) in Main at REPL[14]:1

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [March 25, 2019, 11:56am UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/2 "2019-03-25T11:56:09Z")

</div>

> [@bkamins](#):
>
> I wanted to make sure that it is an intended behavior

I am not sure what you are trying to do, but this will be

1. very confusing to readers of your code (not sure many people would catch that `T` is global unless they explicitly look for it),

2. completely at odds with Julia’s performance model (baking in type unstable code and dynamic lookups from the very design).

Do you want to restrict to constructors other than `Point{T}(::T, ::T)`? Just defining an inner constructor would do this. Or restrict `T` further? Again, you can check in the inner constructor. Not sure what the role of the global is here.

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [March 25, 2019, 12:05pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/3 "2019-03-25T12:05:40Z")

</div>

This does seem like an `antipattern`. In general, you should not be relying on globals for local effects – especially when those effects are not necessary.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [March 25, 2019, 12:07pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/4 "2019-03-25T12:07:31Z")

</div>

I don’t think he is asking if doing this is a good idea, but if it is intended for `T` to bind to global variables when defining structs and methods where you typically put `TypeVar`s. It seems quite brittle.

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [March 25, 2019, 12:10pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/5 "2019-03-25T12:10:28Z")

</div>

`T` is but a name. It’s kind of an unfortunate name for a global, but I certainly wouldn’t consider Julia’s behavior here to be surprising. Consider the case that `T` in the original example were replaced with `ComplexF64`, which is just short for `Complex{Float64}` (as in there’s a statement `const ComplexF64 = Complex{Float64}` somewhere). Would anyone still be surprised by Julia’s behavior?

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [March 25, 2019, 12:13pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/6 "2019-03-25T12:13:33Z")

</div>

I would support making type parameters local to their context.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [March 25, 2019, 12:15pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/7 "2019-03-25T12:15:05Z")

</div>

> [@tkoolen](#):
>
> Would anyone still be surprised by Julia’s behavior?

A bit. I would have assumed you would write that as `struct Foo{T <: ComplexF64}`?

---

<div class="post-metadata">

### Author: ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)
#### Post date: [March 25, 2019, 12:36pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/8 "2019-03-25T12:36:52Z")

</div>

> [@kristoffer.carlsson](#):
>
> It seems quite brittle.

This is exactly the point. I know that you cannot avoid problems in all cases, as obviously you can write e.g.:

```julia
julia> Int64 = String
String

julia> Int64
String

julia> z = Int64[]
0-element Array{String,1}

```

but the point is that it is natural to assume that type parameters are local to their context as @JeffreySarnoff writes.

And I understand that in the past (pre `where`) Julia worked this way and this behavior has changed when `where` was introduced. My question was if this change was intentional or not.

---

<div class="post-metadata">

### Author: ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)
#### Post date: [March 25, 2019, 1:04pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/9 "2019-03-25T13:04:31Z")

</div>

> [@bkamins](#):
>
> type parameters are local to their context as @JeffreySarnoff writes.

I believe the type parameter `T` is local inside the `struct` (e.g. `x::T` still refers to the local `T`). It’s just that for constructors, the local names are not looked up, because they are only bound when you have an actual object:

```julia
julia> struct Foo{S}
           Foo{S}() = new{S}()
       end
UndefVarError: S not defined

```

this should be:

```julia
struct Foo1{S}
    Foo1{S}() where S = new{S}()
end

```

I suppose that it could have looked in the `struct` so it would have been an error when a constructor definition refers a name in that scope, so that your original example would error too. But at this point that would be a breaking change to the language.

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [March 25, 2019, 1:08pm UTC](https://discourse.julialang.org/t/parametric-inner-constructor-inherits-parameter-from-global-scope/22296/10 "2019-03-25T13:08:59Z")

</div>

There are three things going on here:

- The name `T` is just like any other name, like `TT` or even `Int`. When you define a method, the types need to be identified by _something_ — and that thing can be (and almost always is) a global name. Typically it’s a constant global, but it can be non-constant, too. It’ll just define the method based upon the value when the method was defined.

- The syntax `Point{Int}(...) = ...` is defining a constructor for `Point{Int}`. Before the `where` revolution, this syntax meant something completely different — it was how we introduced local type variables for a method signature. So yes, the meaning here changed (and did so dramatically) and it was very intentional — the disambiguation between defining a method on `Point{Int}()` vs. a method on `Point()` is a huge benefit from the `where` clause.

- We introduce type parameters for structs in their definition: the syntax `struct Point{T}` is how we introduce a local name `T` that can be used in field definitions and the parameters of supertypes. Now here’s the confusing part — that `T` isn’t available to inner constructors, even though it’s written within the same indented block. In fact it cannot be because when you call an inner constructor the `Point` hasn’t be constructed yet so it doesn’t know what that `T` is! The inner constructor can even _change_ what the parameter is compared to how it was called:
