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

possible missing promote_type #5588

Closed
vtjnash opened this issue Jan 28, 2014 · 8 comments
Closed

possible missing promote_type #5588

vtjnash opened this issue Jan 28, 2014 · 8 comments
Labels
help wanted Indicates that a maintainer wants help on an issue or pull request speculative Whether the change will be implemented is speculative

Comments

@vtjnash
Copy link
Member

vtjnash commented Jan 28, 2014

julia> promote_type(Rational, Float64)
ERROR: no promotion exists for Rational{T<:Integer} and Float64
 in promote_type at promotion.jl:110

came up in vtjnash/Polynomial.jl#12

@JeffBezanson
Copy link
Member

There are promotions for instantiated versions of Rational (e.g. Rational{Int}).

@vtjnash
Copy link
Member Author

vtjnash commented Jan 28, 2014

I realize that, but the user gave an array of type Rational, and my code was attempting to guess the output type for the array. Even better would be to take advantage of type inference. Can we add the following to Base?

macro static_typeof(expr)
    Expr(:static_typeof, esc(expr))
end

@JeffBezanson
Copy link
Member

I don't think that will help in this case; the lack of a promotion rule for that means type inference also doesn't know what the result should be. For example promote_type(Rational{BigInt},Float64) is BigFloat.

You really want to avoid static_typeof. There are many cases where inference gets an imprecise type, and the worst that can happen is something runs a bit slower. If it's not in a bottleneck it might not even matter. But with static_typeof, your program might not work. You can't rely on inference to always give the answer you want.

@vtjnash
Copy link
Member Author

vtjnash commented Jan 28, 2014

Currently, I'm simulating static_typeof with promote_type, which is even worse. I'm trying to guess the best storage for allocating an array for the output of an expression like [1,2,3] / N. But I really want whatever static_typeof is able to determine, without seriously convoluting the code to make it fit into a comprehension: [i/N for i = 1:3]

@JeffBezanson
Copy link
Member

In this case, at the moment, static_typeof would probably give Any. Happy?
The good thing about promote_type is it has to obey your definitions;
inference can do whatever it wants.
On Jan 28, 2014 1:22 AM, "Jameson Nash" notifications@github.com wrote:

Currently, I'm simulating static_typeof with promote_type, which is even
worse. I'm trying to guess the best storage for allocating an array for the
output of an expression like [1,2,3] / N. But I really want whatever
static_typeof is able to determine, without seriously convoluting the
code to make it fit into a comprehension: [i/N for i = 1:3]

Reply to this email directly or view it on GitHubhttps://github.com//issues/5588#issuecomment-33454067
.

@vtjnash
Copy link
Member Author

vtjnash commented Jan 29, 2014

static_typeof actually seems to work quite well at not giving Any (assuming this is in a function and N is known -- I don't expect it to be magical). Cases where it seems like it would be useful:

Ensuring type-stability of short-circuiting code:

function f(x)
  if iserror_condition(x)
    return oftype(@static_typeof y, 0)
  end
  y = do_something_complicated(x)
  return y
end

Initializing loop variables with a best guess type:

function g(x)
  y = oftype(@static_typeof x/1, 1)
  for i = 1:10
    y += x/y
  end
  y
end

Preallocating arrays with a best guess type:

function h(x)
  s = start(x)
  if done(x,s)
    return Array(@static_typeof op(x), 1)
  end
  xi, s = next(x,s)
  lenx = length(x)
  y = Array(@static_typeof op(xi), lenx)
  y[1] = xi
  for i = 2:lenx
    xi, s = next(x,s)
    y[i] = op(xi)
  end
  y
end

@JeffBezanson
Copy link
Member

I think we need a better approach than this. This is first of all ugly, and the first case doesn't work since y at that point is not defined. Maybe we could do something like a declaration, but where you let the compiler pick a convenient type for the variable. e.g.

    y::please_pick = 0
    for x in z
        y += x
    end
    y

Basically indicating that the assignment from 0 should not be taken type-literally.

@vtjnash
Copy link
Member Author

vtjnash commented Jan 29, 2014

Empty type definition y:: = 0 or add behavior to ANY y::ANY?

I like the idea, to the compiler it would mean: "ignore this line in computing type information for this variable, then use convert() after-the-fact to patch it up"

For the first case, we might want something like the following, which would cause a call to convert to be added to that return statement, such that the function has a minimal number of return types.

function f(x)
  if iserror_condition(x)
    return::ANY 0
  end
  y = do_something_complicated(x)
  return y
end

I don't know how to express the third option here. But two out of three seems like a huge gain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Indicates that a maintainer wants help on an issue or pull request speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

2 participants