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

[doc] rename outer-only constructors? #23022

Open
Gnimuc opened this issue Jul 29, 2017 · 8 comments
Open

[doc] rename outer-only constructors? #23022

Gnimuc opened this issue Jul 29, 2017 · 8 comments
Labels
docs This change adds or pertains to documentation Hacktoberfest Good for Hacktoberfest participants

Comments

@Gnimuc
Copy link
Contributor

Gnimuc commented Jul 29, 2017

As discussed here, the outer-only constructor SummedArray(a::Vector{T}) is actually an inner constructor. Shall we pick up a better name or add some additional info for clarification?

julia> struct SummedArray{T<:Number,S<:Number}
           data::Vector{T}
           sum::S
           function SummedArray(a::Vector{T}) where T
               S = widen(T)
               new{T,S}(a, sum(S, a))
           end
       end

julia> SummedArray(Int32[1; 2; 3], Int32(6))
ERROR: MethodError: no method matching SummedArray(::Array{Int32,1}, ::Int32)
Closest candidates are:
  SummedArray(::Array{T,1}) where T at none:5
@fredrikekre
Copy link
Member

Where does it say it is an outer constructor?

@tpapastylianou
Copy link

tpapastylianou commented Jul 29, 2017

Judging from your title, there is still some confusion.

The documentation at that point is not saying that this definition:

       function SummedArray(a::Vector{T}) where T
           S = widen(T)
           new{T,S}(a, sum(S, a))
       end

is an "outer-only constructor".

The role of that function is described in this passage:

Therefore we want to avoid an interface that allows the user to construct instances of the type SummedArray{Int32,Int32}. One way to do this is to provide a constructor only for SummedArray, but inside the type definition block to suppress generation of default constructors

(emphasis mine). Defining this "inside" the type definition block means this is an "inner" constructor.

What "outer-only constructors" refers to in that section is this: If you write something like the above, this "suppresses generation of default constructors"; if you don't, generation of default constructors takes place normally. And as per the bit a couple of subsections above that passage, this involves both implicit inner and outer constructors, such as:

This automatic provision of constructors is equivalent to the following explicit declaration:

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

julia> Point(x::T, y::T) where {T<:Real} = Point{T}(x,y);

Therefore, if a "blocking" explicit inner constructor has been provided, these implicit inner constructors are no longer available. You can't use them. And for that reason, you can rely on "outer constructors only" (hence the title of the section) of your creation, that necessarily act as wrappers to the explicit inner constructor you defined.

Therefore, in the SummedArray example, the presence of that inner constructor, prevents you from being able to create an instance of type SummedArray{Int32,Int32}, since there is no way for you to write an outer constructor (a wrapper) that can create such an instance via the explicit inner constructor provided. But if that explicit inner constructor had not been defined, then the default implicit ones that would then generally apply would allow you to simply do SummedArray(Int32[1; 2; 3], Int32(6)) as normal. (which is what that section is trying to say).

@Gnimuc
Copy link
Contributor Author

Gnimuc commented Jul 29, 2017

So there are no outer-only constructor examples within that section?
(Maybe I should go back into middle school and study hard on English 🤔 )

✅ A women-only [space] is a physical [area] where only women are allowed.
❌ An outer-only [constructor] is a [constructor] where only outer constructors are allowed.

✅ The English-only [movement] is a political [movement] for the use of only the English language in
❌ An outer-only constructor is a [constructor] for the use of only the outer constructors in type definition.

@tpapastylianou
Copy link

tpapastylianou commented Jul 29, 2017

No there are not. :)
An inner constructor is a constructor defined inside the type definition.
An outer constructor is one defined outside the type definition.

There's no such thing as an "outer-only constructor".
I will agree with you that the section's title may be a bit misleading in that sense, and that perhaps the section itself could have been fleshed out a bit more, and could differentiate more clearly between 'default inner' vs 'explicit inner' constructors, instead of just referring to both as "inner" constructors without clarifying the context.

The point of that title is simply to point out that "there are cases where the user of a type cannot rely on default inner constructors to create instances for that type, because these have been explicitly blocked by the presence of an explicit inner constructor". And therefore the user can only call that explicit constructor, or create more outer constructors that necessarily involve calling the explicit inner constructor within their function definition. But that's their only option; the option to use the default inner constructors simply doesn't exist. (hence, I guess, why they called the section "outer-only").

@Gnimuc
Copy link
Contributor Author

Gnimuc commented Jul 29, 2017

@tpapastylianou After some investigation, I find something interesting in this post #8135 (comment) :

Invariants are enforced by the restricted availability of new. However I could imagine defining an outer constructor inside a type block:

type Foo{N}
x::NTuple{N,Int}

call{N}(::Type{Foo}, x::NTuple{N,Int}) = new{N}(x)
end
That would ensure that Foo((1,2)) is the only way to actually construct a Foo. new{N} would be new special syntax that lets you specify the type parameters to construct with.

It seems the original idea is to make "outer-only" constructor an truly outer constructor.

@fredrikekre maybe here ;)

@tpapastylianou
Copy link

Well, I may be wrong in my interpretation of that thread, but again, I think this is not the case, and the confusion again is produced from using "outer" and "inner" in different contexts.

The pertinent comment setting the context in that thread is this one, i.e. the fact that the syntax "Foo{N}" means different things in the context of a type definition and its inner constructor vs in the context of an outer constructor definition. I.e. one acts as a 'concrete' method on a parametric (but fully specialised at the time of instantiation) type, the other acts as a parametric method where the parameter will essentially dictate which specialised inner constructor to call -- subtle difference but not quite the same thing. But, Jeff is saying there could conceivably be a way to create an inner constructor in a hacky way (by overloading the call function) such that it simulates "outer constructor semantics". But technically that would still be an inner constructor, since it's defined inside the type block.

In any case, I don't think the two threads are that related, apart from the fact that in both there is potential for confusion because the distinction between default vs explicit is never made clear :)

@Gnimuc
Copy link
Contributor Author

Gnimuc commented Jul 30, 2017

However, @JeffBezanson gave another definition of inner/outer constructor in the thread below:

An outer constructor will just be a method of Type{A}, and an inner constructor will be a method of Type{A{N}}.

Following this definition(forget the definition concerning type block in the doc), you'll find what I said in that SO post is actually right. I hadn't read this definition before, I made the deduction from the outputs of @which/methods and from the assumption that SummedArray(a::Vector{T}) is an example of outer-only constructor which is a kind of outer constructor. As what I said:

hmmm, an outer constructor IN a type declaration block, and it calls new as well. I guess the purpose here is just to prevent Julia from defining the default inner-outer constructor pair for us, but is the second statement from the doc still true in this case? I think it's confusing to new users.

if the assumption holds true(i.e. like Jeff said "An outer constructor will just be a method of Type{A}"), obviously the definition of inner constructors from the doc should be corrected. That's why I asked the question -- What on earth is an inner constructor?

The point here is simply a naming thing, using which definition depends on what the original author thought. The outer-only constructor section is written by Jeff, let's wait for him to answer whether

function SummedArray(a::Vector{T}) where T
    S = widen(T)
    new{T,S}(a, sum(S, a))
end

is an outer constructor or not 😕😕😕

@Gnimuc
Copy link
Contributor Author

Gnimuc commented Jul 30, 2017

@tpapastylianou As @StefanKarpinski said in this post:

The syntax used to define a method always matches the syntax used to call it.
The F{T} syntax always refers to the type F with parameter T.

the ambiguity of Foo{N} will be resolved in the future, deprecating old inner constructor syntax for parametric types is the first step. In this sense, function SummedArray(a::Vector{T}) where T shouldn't be considered as an inner constructor.

@kshyatt kshyatt added the docs This change adds or pertains to documentation label Jul 31, 2017
@fredrikekre fredrikekre added the Hacktoberfest Good for Hacktoberfest participants label Sep 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation Hacktoberfest Good for Hacktoberfest participants
Projects
None yet
Development

No branches or pull requests

4 participants