-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
possible changes to inner constructors #8135
Comments
This behavior is documented here. Consider this case:
How should it guess the value of N in that case? That's the job of the outer constructor. |
Ah, right—I guess you're referring to:
Yeah, I remember reading that. It also says that not supplying a constructor is equivalent to
The example is type T{N}
t::NTuple{N,Int}
end Now you can easily use type T{N}
t::NTuple{N,Int}
T(t) = new(t)
end But it doesn't. And I still don't understand why. I see that what you point to is an important point here. Should the inference be done based on the parameters to the inner constructor or to the parameters to In either case, I don't quite see the argument for requiring this to be done in an outer as opposed to an inner constructor. As I understand it, the main point of inner constructors is (i) to enforce invariants, and (ii) create self-referential objects, no? Why does this negate inference of type parameters? |
I guess one issue might be that by default you have both a constructor |
In fact, the docs explicitly say that the following two types are equivalent… type T1
x::Int64
end
type T2
x::Int64
T2(x) = new(x)
end |
You're right, those statements do muddle the waters. My understanding is that both an outer and an inner constructor are created by default, and defining your own inner constructor nixes the construction of the default outer constructor. See the Rational example at the bottom of that page. Pull requests improving the documentation would be welcome! As someone who tripped over the current docs, you're ideally suited to make it clearer---no one could do a better job than you 😄. |
Thanks for the vote of confidence ;-) I see that there are parts of the docs I ignored at the moment (though I have read them before). I guess I should re-read that material first, at the very least :-} |
BTW: As far as I can see, the inner constructor is also of the form |
Ah, no I think I understand. The inner constructor is defined for any concrete instantiation of the type, whereas the outer constructor gan be generic wrt. the type parameters—right? |
The way I think about it is that the inner constructor runs with the parameters already fixed. |
Not sure if this helps, but the type parameters have somewhat different meanings in types and outer constructors. For types, the type parameter is part of the type name. So On the other hand, outer constructors are just functions, so the type parameter indicates that the Type should be extracted from the passed in parameters, and then is itself usable in the function, e.g., when creating a parametrized type. So in T{N}(a::N) = T{N,5}() the first |
An observation I take away from this is that there's a "missing combination" of sorts: you can't have a type with only an outer constructor (you can have both, or only an inner constructor). In theory it is perfectly coherent to define this outer constructor:
with no inner constructor. Then you could write For this type, this arrangement is desirable since it removes redundancy: there is no need to be able to write With the planned changes to constructors, defining such a thing will actually be possible, with syntax backwards-compatibility being the only pain point. An outer constructor will just be a method of |
Thanks for the clarifications, @timholy and @kmsquire! @JeffBezanson: The redundancy you speak of would be an issue for any type without an external constructor, wouldn't it? (You'd never want to specify a type parameter that contradicted the parameters? You you might want to use an abstract supertype, I guess.) And if this type had only an external constructor, that wouldn't be usable for the “invariant enforcement,” I guess—as one could just add another constructor…? The planned changes sound interesting; is there an issue or the like somewhere? (And: Any reason why |
#1470 is one related issue. Invariants are enforced by the restricted availability of
That would ensure that This issue is actually very helpful. I had not thought through all of this before. |
Huh—cool! Read through the discussion on #1470; quite a bit to digest. I guess the reason for using That is, one could have had something like… type Foo{N}
x::NTuple{N,Int}
Foo{N}(x::NTuple{N,Int}) = new{N}(x)
end …? Or are the semantics different, in that defining |
By the way, something along the lines of the example above (just with a call to plain |
I like adding constructors by explicitly adding methods to The idea was that inside the One possibility is for
so the syntax is not entirely lying --- the first {N} is still a "method parameter" as normal. However we need to make all three possibilities accessible:
I can think of some extreme hacks. We could pick between the 2nd and 3rd forms automatically based on whether the names of the type parameters appear in the method signature. For example
and
@StefanKarpinski might want to chime in here. |
I'm going to reopen this since it's a good discussion of constructor design in light of |
The |
I'm trying to create a type whose inner constructor does some adjustment/normalization, and at the same time I want to deduce type parameters from the constructor arguments. And I'm having trouble making that work…
The following works, and it solves my problem, but I don't quite understand why it should be necessary, and I wonder if it might be a bug that it is?
As @tknopp pointed out, it seems the default constructor is removed.
Could I somehow override the more specific default constructor (which doesn't have
Any
-arguments), and supply the proper type parameter tonew
or something? (Haven't been able to make that work.)(See also discussion on Julia-Users.)
The text was updated successfully, but these errors were encountered: