-
-
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
Arithmetic on types? #8027
Comments
Now this gets into some interesting territory. Currently julia's domain has two "levels": values and types. You go from values to types via a An alternate formulation would be to insist that everything be part of the lattice. There would be no I believe this second design is the only reasonable way to support Ultimately we need approaches that will work for e.g. #7258 (comprehensions). An example is Line 1298 in 3af5019
map ).
This is a hard problem, but I'm not yet in favor of actually writing |
I'm not disagreeing exactly, but I think it's worth asking seriously: why is this so bad? Compared, say, to fixing code like this and heroics like this? It would be nice to be able to define function map(f::Function, A::AbstractArray{T})
output = similar(A, f(T))
for i = 1:length(A)
output[i] = f(A[i])
end
output
end We could have macros like
and get expanded to
With a few other similar tricks to handle cases where |
I agree A requirement that every definition also need or imply some other definition can only be a language feature; I don't want to tack it on with macros. We could possibly add notations for explicitly computing in the type domain, e.g. writing |
That is indeed an interesting and very different alternative, but I'm not Monotonicity constraints on function return types as discussed in e.g. Btw: I implemented some arithmetic on types explicitly in broadcast.jl just |
That's a really interesting idea. I like it. We could probably already be using @toivoh, I agree this interacts closely with type declarations on function outputs. |
I really like this idea, as you already know. @JeffBezanson, I think that you already have to write
and
The last one has the advantage of avoiding the value level which is useful because
and
|
@andreasnoackjensen, At a bare minimum, we need it to be |
It was not meant as a defense for Generally, I think we agree pretty much on this issue and in particular I think it makes really good sense to do promotion with respect to some operation. However, @StefanKarpinski and @JeffBezanson seemed to disagree when I proposed that, so it might be that my understanding of promotion is wrong. |
The argument that there is already duplication, and so we can/should do more, does not work for me. The ultimate goal should be to remove the duplication. The second best option is for the duplication to be very obvious, e.g.
Adding definitions to I agree there is not a big difference between that and
|
I'm happy with whatever solution allows one to allocate instances of output arrays with the appropriate type even if:
I do like the idea of leveraging |
@JeffBezanson, I don't understand the consequences of your first idea well enough to see how many new duplicates are needed. I'm only saying that duplication is already necessary for a lot of the array code.
Yes. That would be great.
I think this the purpose of type arithmetic
It wasn't meant as an idea for implementing this, so I should probably have skipped that part. @timholy, Isn't it a problem that |
That is a good summary of requirements. I think we could have a Once code is in the form
There seems to be some hope of making the snake eat its tail, and folding the two |
I think this is the discussion It never became a pull request so it is a bit hidden. |
@andreasnoackjensen, yes, we'd need a version that works on expressions, too. But I think it's the same basic idea: leverage the type-inference machinery. I had forgotten about that previous discussion, thanks for the link. |
There's also #5588 (comment), #6114 (comment), and my PR #6692, although I closed that recently because I thought we were trying to move away from having return types depend on type inference. But in this case, maybe there is not a tractable alternative? |
Yes, we do want to avoid it as much as possible. But there seem to be cases where you really do need a good guess for the element type before computing anything. |
The whole point of the monotonic return types idea (see the thread and discussion in #1090) was that it would provide upper bounds on return types that would be more predictable and not depend on type inference. Of course, adding return type annotations on methods could be seen as a slight duplication, and I know it's probably a bit complex to implement. Still, anyone care to comment on this alternative? |
I still like the idea of monotonic return types, but I worry that it has an extreme non-locality property: you write a new method and it returns a value of a type that is completely unrelated to the code you wrote. By the same token, behavior of code you write can change when someone else changes their code. One possibility to deal with that if a "supermethod" has a type annotation, then all its "submethods" must have a type annotation or a warning is printed; if the type annotation of submethod is not a subtype of its supermethods, that should also be a warning (or maybe an error). That lets you hack things out without bothering with type annotations, getting a few warnings, but means that you get early warning if a non-local interaction between supermethods and submethods changes. |
Completely agree, there should at least be a warning if there is a submethod that has a less strict return type annotation than its supermethods, otherwise this could lead to lots of unintended breakage. That will cause some inertia in the return type annotations, especially in deep hierarchies, but I think most hierarchies will not be that deep. I guess an absent return type annotation would be the same as |
That seems good. Having |
Let's move this part of the conversation over there for posterity. |
For my own clarification, what's the difference between a "supermethod" and a "submethod"? Does it have to do with generality of the method arguments? (i.e. more abstract args = supermethod?) |
If the tuple of argument types of method A is |
The most general argument signature is |
Unless we support general singleton types, in which case |
A C++'s type Value{v} end
typealias VType{v} Type{Value{v}}
f(::VType{5}) = 0
f{v}(::VType{v}) = v
f(v::Int) = f(Value{v}) # for user convenience Is it the case that a call to |
Yes, currently However things get worse when the
Here a "typical" call to |
The "convenience" syntax is only optional. For "internal" functions called with compile time values, usage of # sugar for: f(x::Int) = if x==1; 0; else x^2; end
f(x::Int) = x^2
f(1) = 0 I just mean to say that |
Any new progress along this? I often find the need of a way to get the return type. |
@lindahua Does |
Can you give an example of how you'd use a stagedfunction for this? |
I will work out an example for myself - which will probably answer my own question, or have me ask more questions about staged functions. |
Working on solving the ambiguity warnings caused by #12115 by exploiting generic fallbacks, I've come to think that This issue fits "Arraymagedon" very well, since it invariably crops up whenever one wants to define arithmetic on weird types and support such operations for arrays of such types. So I'm giving this a 0.5 milestone. |
promote_op(F, R, S) computes the output type of F(r, s), where r::R and s::S. This fixes the problem that arises from relying on promote_type(R, S) when the result type depends on F.
We've had quite a few issues crop up about how to define types of outputs given inputs. My view is that this is revealing limitations in the promotion system. A proposal to deal with this might be to define arithmetic on types.
For example, here would be some rules:
and so on.
The text was updated successfully, but these errors were encountered: