#606 Partial closure type inference?

tompalmer Fri 22 May 2009

I made some code that looks about like this (simplified here):

list := [1, 2, 3]
list.reduce(0) |a, b| {return a * b}

I got this error:

Unknown method 'sys::Obj.mult'

Well, I figured out I had at least one error after reviewing the spec again:

Obj? reduce(Obj? init, |Obj?, V, Int -> Obj?| c)

So, I thought, "Well, I just need to put a type on that first param, since it's not a V." So, this was my take 2:

list.reduce(0) |Int a, b| {return a * b}

Same error. I don't know why, since a should now be of type Int. Maybe a different error if it decided not to infer the type of b. Well, I added the type of b for good measure:

list.reduce(0) |Int a, Int b| {return a * b}

That produced a new error:

Cannot return 'sys::Int' as 'sys::Void'

Hmm. Seems it can't infer a return type at this point, so I need to be explicit:

list.reduce(0) |Int a, Int b -> Int| {return a * b}

That compiles.

I'd like to think that my second version above (i.e., list.reduce(0) |Int a, b| {return a * b}) would work. Is it meant to work, or am I going beyond current expectations?

I included a full story because it adds additional bug reports (such as why the error didn't at least change for my second version) or ideas of mistakes folks could make (such as my original mistake at first).

brian Fri 22 May 2009

I don't support partial inference right now - if you declare only one type param, then the other params will default to Obj? (not be inferred) and return will default to Void.

tompalmer Fri 22 May 2009

Thanks for the reply. Do you know why the error didn't change for an Int times an Obj??

Side note, my first arg in all the examples above should have been a 1. Just sheepishly admitting a mistake before someone gets confused or calls me on it.

brian Fri 22 May 2009

Thanks for the reply. Do you know why the error didn't change for an Int times an Obj?

Probably a bug - I am probably treating a partial declaration as an un-inferred function signature with all parameters as Obj?. I've to take a look.

brian Wed 27 May 2009

I've given this some more thought, and I'm not sure what the right design should be.

  • Should we allow you to partially specify some types in a function, and omit others to be inferred?
  • Under what circumstances should we imply the function type to be Void versus infereing it?

tompalmer Wed 27 May 2009

Should we allow you to partially specify some types in a function, and omit others to be inferred?

I personally think that would be great.

Under what circumstances should we imply the function type to be Void versus infereing it?

Seems that today you can give a Void function where a return value is expected. Are there good use cases to support this? If not, it seems like you could always require (and somewhat infer) a return type. Or perhaps even go for the most common case. Would you most commonly want the return type inferred? Or would you most commonly want a function expecting a return value to be Void instead?

Make the most common case easiest, if all else is equal. So, if this is changed (and I think I lean that way myself), I'd say require -> Void to change the expectations from non-void to void. But I haven't done a full survey of use cases just now or anything.

brian Wed 3 Jun 2009

Promoted to ticket #606 and assigned to brian

Need to define the formal rules for this. At the very least, I think we need to support inference of params with an explicit return type (to work with changes to List/Map map methods)

tompalmer Wed 3 Jun 2009

Personally, I'd go as far as possible with this. Unspecified return types should be inferred as far as possible, I think (whether by expected type and/or by types returned in the function).

brian Thu 25 Jun 2009

// resolved

brian Thu 25 Jun 2009

Ticket resolved in 1.0.45

I changed code to support partial type inference as part of fix for 651.

If explicit parameter types or a return type is provided then it overrides the inferred signature.

However note that if the function parameters are fully specified, then the return type is Void, not inferred from parameter being used with closure. Need to think about that one.

See the tests in ClosureTest.testInference for how I have it working now.

tompalmer Thu 25 Jun 2009

Sounds great.

However note that if the function parameters are fully specified, then the return type is Void, not inferred from parameter being used with closure. Need to think about that one.

I lean towards still letting it be inferred, but I might not have thought through everything.

Login or Signup to reply.